13년차의 서버실

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

[작성자:] admin

  • [Proxmox] Proxmox Backup Server (PBS) vs. 스크립트 백업: 홈랩 비용 효율성 비교

    [Proxmox] Proxmox Backup Server (PBS) vs. 스크립트 백업: 홈랩 비용 효율성 비교

    홈랩 백업, 정말 고민되시죠? Proxmox Backup Server (PBS) vs. 스크립트 백업 비용 효율성 비교

    안녕하세요, 13년차의 서버실 주인장입니다. 홈랩을 운영하면서 가장 중요하게 생각하는 것 중 하나가 바로 백업(Backup)입니다. 아니, 중요하게 생각해야만 하는 것이죠. 처음엔 저도 ‘설마 내 데이터가 날아가겠어?’ 하는 안일한 생각으로 버텼습니다. 그러다 한 번 크게 데이터 유실(Data Loss)을 겪고 나서야 정신을 차렸죠. 그 이후로 백업은 제 홈랩 운영의 제1원칙이 되어 버렸습니다.

    특히 Proxmox VE(Virtual Environment)를 사용하시는 분들이라면, 가상 머신(VM)이나 컨테이너(LXC) 백업에 대한 고민이 많으실 거예요. 스냅샷(Snapshot)만 믿고 계신 건 아니겠죠? 스냅샷은 편리하지만, 물리적 저장 장치에 문제가 생기면 함께 날아간다는 치명적인 단점이 있습니다. 그래서 별도의 백업 솔루션이 필수적인데, 여기서 많은 분들이 Proxmox Backup Server (PBS)를 쓸지, 아니면 스크립트 기반의 백업을 직접 구현할지 고민하시더라고요. 저도 그랬거든요!

    오늘은 13년차 인프라 엔지니어의 경험을 바탕으로 이 두 가지 Proxmox 백업 전략의 비용 효율성(Cost Efficiency)을 비교 분석해보고, 홈랩 환경에서 어떤 선택이 더 현명할지 함께 이야기해보려 합니다. 특히 Proxmox Backup Server 비용에 대한 오해도 풀어드릴게요!

    Proxmox Backup Server와 스크립트 백업 아키텍처 비교 다이어그램

    Proxmox Backup Server와 기존 스크립트 백업 솔루션을 비교하는 개략적인 아키텍처 다이어그램입니다. 각 방식의 데이터 흐름과 구성 요소를 시각적으로 보여줍니다.

    Proxmox Backup Server (PBS)와 스크립트 백업, 뭐가 다를까요?

    우선 두 가지 방식의 핵심 개념부터 간단히 짚고 넘어가겠습니다. 쉽게 말해 이렇습니다.

    • Proxmox Backup Server (PBS): Proxmox 개발사에서 공식적으로 제공하는 전용 백업 솔루션이죠. Proxmox VE와 완벽하게 통합되어 VM, LXC 백업 및 복원을 쉽고 효율적으로 처리할 수 있도록 설계되었습니다.
    • 스크립트 백업 (Script Backup): rsync, dd, tar 같은 리눅스 명령어나 Proxmox VE 자체의 vzdump 명령어를 활용하여 직접 스크립트를 짜서 백업을 수행하는 방식입니다. 특정 백업 스토리지를 마운트해서 데이터를 밀어 넣는 형태가 되겠죠.

    PBS의 가장 큰 장점은 바로 중복 제거(Deduplication)와 증분 백업(Incremental Backup)입니다. 예를 들어, 제가 Ubuntu VM을 여러 개 돌리고 있는데, 얘네들이 대부분 비슷한 OS 파일을 가지고 있잖아요? PBS는 이 중복되는 블록을 한 번만 저장하고, 변경된 부분만 추가로 저장해서 저장 공간을 엄청나게 절약해줍니다. 그리고 백업 데이터의 무결성 검사(Data Integrity Check) 기능도 강력해서, 백업 데이터가 손상되지 않았는지 주기적으로 확인해주는 점도 정말 마음이 놓이더라고요.

    반면 스크립트 백업은 모든 것을 직접 제어할 수 있다는 장점이 있습니다. 원하는 대로 커스터마이징(Customizing)이 가능하고, 이미 있는 리소스(Resource)를 활용해서 추가적인 소프트웨어 설치 없이 바로 사용할 수 있거든요. 하지만 중복 제거 같은 고급 기능은 직접 구현하기 어렵고, 백업 데이터의 관리가 번거로울 수 있습니다.

    PBS, 직접 써보니 이렇더라고요! (실전 구현)

    제가 PBS를 처음 써봤을 때 느꼈던 감정은 ‘와, 이거 진짜 편하네!’ 였습니다. 사실 처음엔 PBS를 위한 별도의 서버나 VM을 구성해야 한다는 생각에 약간의 진입 장벽을 느꼈거든요. ‘그냥 vzdump로 NAS에 밀어 넣으면 안 되나?’ 싶었죠. 근데 PBS를 설치하고 Proxmox VE에 백업 스토리지로 연결해보니, 그 편리함에 금세 빠져들었습니다.

    설치 자체는 Proxmox VE와 마찬가지로 ISO 이미지를 통해 쉽게 할 수 있습니다. 혹은 기존 리눅스 서버에 패키지로 설치하는 것도 가능하더라고요. 저는 홈랩에서 쓰지 않는 미니 PC에 PBS를 설치하거나, Proxmox VE 위에 하나의 VM으로 올려서 사용하기도 했습니다. (물론 이 경우 백업 대상 VM과 동일한 물리 서버에 있으면 안 되겠죠?)

    # PBS 설치 후 Proxmox VE에서 백업 스토리지 추가하는 예시
    # Datacenter -> Storage -> Add -> Proxmox Backup Server 선택
    # ID: pbs-backup
    # Server: [PBS 서버 IP 또는 도메인]
    # Port: 8007 (기본값)
    # Username: root@pam
    # Password: [PBS root 비밀번호]
    # Datastore: [PBS 데이터스토어 이름, 예: mybackup]
    

    이렇게 PBS 스토리지를 Proxmox VE에 연결하고 나면, 백업 스케줄(Backup Schedule)을 설정하는 게 정말 간단해집니다. 웹 UI에서 몇 번의 클릭만으로 특정 VM이나 모든 VM을 원하는 주기로 백업하도록 설정할 수 있어요. 압축(Compression) 알고리즘 선택부터 보존 정책(Retention Policy) 설정까지 GUI(Graphical User Interface)로 모든 걸 처리할 수 있다는 게 가장 큰 장점이죠. 백업이 성공적으로 완료되면 Proxmox VE 로그에도 잘 남고요. ✅

    Proxmox Backup Server 웹 인터페이스 백업 스케줄 설정

    Proxmox Backup Server의 웹 인터페이스에서 백업 스케줄을 설정하는 화면입니다. 직관적인 GUI를 통해 쉽게 백업 정책을 관리할 수 있습니다.

    스크립트 백업, 장단점 명확합니다 (실전 구현)

    PBS가 나오기 전, 그리고 지금도 많은 분들이 스크립트 백업을 사용하고 계십니다. 저 역시 PBS를 알기 전에는 주로 vzdump 명령어를 활용한 스크립트 백업을 애용했었죠. 다음은 간단한 스크립트 백업 예시입니다.

    #!/bin/bash
    
    # 백업 대상 VM/LXC ID
    VM_IDS="100 101 102"
    
    # 백업 저장 경로 (NFS 또는 SMB 마운트된 디렉토리)
    BACKUP_DIR="/mnt/pve/nas_backup/vzdump"
    
    # 백업 파일 보존 일수
    RETENTION_DAYS=7
    
    # 백업 실행
    for VM_ID in $VM_IDS;
    do
      echo "$(date '+%Y-%m-%d %H:%M:%S') - Starting backup for VM/LXC $VM_ID..."
      vzdump $VM_ID --mode snapshot --compress zstd --storage local-lvm --dumpdir $BACKUP_DIR
      if [ $? -eq 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') - Backup for VM/LXC $VM_ID completed successfully."
      else
        echo "$(date '+%Y-%m-%d %H:%M:%S') - Backup for VM/LXC $VM_ID failed!" >&2
      fi
    done
    
    # 오래된 백업 파일 삭제 (보존 정책)
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Cleaning up old backup files..."
    find $BACKUP_DIR -type f -name "vzdump-*.vma.zst" -mtime +$RETENTION_DAYS -delete
    
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Backup script finished."
    

    이 스크립트를 cron에 등록해서 주기적으로 실행하면, 원하는 VM들을 백업할 수 있습니다. 장점은 명확해요. 자유로운 커스터마이징이 가능하고, 별도의 소프트웨어 설치 없이 Proxmox VE에 내장된 기능만으로 백업을 구현할 수 있다는 점이죠. 기존에 가지고 있던 NAS나 여분의 하드디스크를 마운트해서 백업 저장소로 활용하기도 좋습니다.

    하지만 단점도 있습니다. ⚠️

    • 중복 제거 기능 부재: VM이 많아질수록 백업 공간을 비효율적으로 사용하게 됩니다.
    • 수동 관리의 번거로움: 스크립트 오류, 저장 공간 부족, 백업 성공 여부 확인 등을 직접 관리하고 모니터링해야 합니다.
    • 복원 과정의 복잡성: PBS처럼 웹 UI에서 클릭 몇 번으로 복원하는 것이 아니라, 명령어를 사용해야 합니다.
    • 데이터 무결성 검사 부재: 백업 파일이 손상되었는지 주기적으로 확인하는 기능이 없습니다.

    특히 중복 제거 기능이 없다는 것은 Proxmox Backup Server 비용 측면에서 간과할 수 없는 부분입니다. 백업 데이터가 늘어나면 늘어날수록 더 많은 저장 장치(Storage)를 구매해야 할 수도 있거든요.

    스크립트 기반 백업 구성도 및 데이터 흐름

    스크립트 기반 백업의 구성도와 데이터 흐름을 보여주는 다이어그램입니다. Proxmox VE에서 백업 스크립트가 실행되어 외부 저장소로 데이터를 전송하는 과정을 나타냅니다.

    비용 효율성, 과연 어떤 선택이 현명할까요?

    자, 그럼 가장 중요한 비용 효율성 측면에서 PBS와 스크립트 백업을 비교해볼까요? 여기서 말하는 ‘비용’은 단순히 하드웨어 구매 비용뿐만 아니라, 시간(Time)과 노력(Effort)까지 포함한 개념입니다. 홈랩에서는 이 ‘시간’ 비용이 생각보다 훨씬 중요하거든요. 제 경험상 삽질하는 시간은 곧 기회비용입니다.

    기준 Proxmox Backup Server (PBS) 스크립트 백업
    초기 설정 시간 별도 서버/VM 구성 필요, Proxmox VE와 연동 용이 (중간) 스크립트 작성 및 테스트 필요 (중간~높음)
    운영 및 관리 시간 웹 UI 기반, 자동화된 스케줄, 모니터링 기능 (낮음) 스크립트 유지보수, 수동 모니터링 필요 (높음)
    저장 공간 효율성 강력한 중복 제거, 증분 백업으로 공간 절약 (매우 높음) 일반적인 압축만 가능, 중복 제거 부재 (낮음)
    하드웨어 비용 별도의 서버/VM 필요 (낮은 사양으로도 충분) (중간) 기존 저장 장치 활용 가능 (낮음)
    데이터 무결성 정기적인 무결성 검사 기능 내장 (매우 높음) 수동 검증 필요, 오류 시 발견 어려움 (낮음)
    복구 편의성 웹 UI에서 쉽고 빠르게 복원 가능 (매우 높음) 명령어 기반, 복잡할 수 있음 (낮음)

    결론부터 말씀드리면, 장기적인 관점에서 Proxmox Backup Server 비용은 스크립트 백업보다 더 효율적일 가능성이 높습니다.

    • 저장 공간 절약: PBS의 중복 제거 기능은 시간이 지남에 따라 엄청난 저장 공간을 절약해줍니다. 이는 곧 추가적인 하드디스크 구매 비용을 줄여준다는 의미입니다. 홈랩에서 데이터가 늘어나는 속도는 상상 이상이더라고요.
    • 시간 절약: 백업 스케줄 설정, 모니터링, 복원 과정의 편리함은 제 소중한 시간을 아껴줍니다. 이 시간을 새로운 기술을 배우거나, 다른 홈랩 프로젝트에 투자할 수 있죠. 삽질 경험을 줄여주는 것이 진정한 비용 절감입니다!
    • 안정성: 데이터 무결성 검사와 쉬운 복구는 만약의 사태에 대비한 훌륭한 보험입니다. 데이터 유실로 인한 정신적, 시간적 손실을 생각하면 PBS의 가치는 더욱 빛을 발합니다.

    물론 PBS를 위한 최소한의 하드웨어(저전력 미니 PC나 라즈베리 파이 같은 SBC에 외장 HDD 연결)는 필요합니다. 하지만 이 초기 투자는 위에서 언급한 장점들로 충분히 상쇄된다고 저는 확신합니다. 특히 홈랩 백업 솔루션을 고민하고 계시다면, PBS는 정말 훌륭한 선택지입니다. 💡

    Proxmox Backup Server와 스크립트 백업의 핵심 장단점 및 장기적인 비용 효율성을 비교하는 인포그래픽입니다.

    삽질 피하기! 제가 겪은 트러블슈팅 경험

    제가 PBS와 스크립트 백업을 사용하면서 겪었던 몇 가지 삽질 경험과 그 해결책을 공유해드릴게요. ⚠️

    1. 스크립트 백업의 저장 공간 부족 알림 부재: 처음 스크립트 백업을 쓸 때는 공간이 부족해지는 걸 모르고 있다가 백업이 실패하는 경우가 많았습니다. 해결책은 간단하더라고요. 디스크 사용량을 체크하는 스크립트를 추가하고, 특정 임계치(Threshold)를 넘으면 제게 이메일이나 메신저로 알림을 보내도록 설정했습니다.
    2. PBS 데이터스토어 용량 부족: PBS는 중복 제거가 강력하지만, 그래도 물리적인 용량은 한계가 있습니다. 특히 백업 데이터를 장기간 보존(Long-term Retention)하다 보면 용량이 차오르죠. PBS 웹 UI에서 데이터스토어 용량을 주기적으로 확인하고, 필요 없는 오래된 백업 스냅샷을 Prune(가지치기) 작업으로 정리해줘야 합니다.
    3. 네트워크 대역폭 문제: 백업은 생각보다 네트워크 자원을 많이 사용합니다. 특히 무거운 VM을 백업할 때, 홈랩 네트워크가 느려지거나 다른 서비스에 영향을 주는 경우가 있었어요. 백업 스케줄을 사용량이 적은 새벽 시간대로 조절하거나, PBS 서버와 Proxmox VE 간의 네트워크를 분리(Dedicate)하는 방법을 사용했습니다.
    4. 권한 문제: 스크립트 백업 시 vzdump 명령어가 특정 디렉토리에 접근하지 못하거나, 마운트된 NAS에 쓰기 권한이 없는 경우가 있었습니다. sudo 권한이나 파일 시스템 권한(chmod, chown)을 꼼꼼하게 확인하는 것이 중요합니다. PBS는 Proxmox VE와의 통합이 잘 되어있어서 이런 권한 문제는 거의 발생하지 않더라고요.

    이런 삽질들을 겪으면서 느낀 건, 결국 자동화되고 안정적인 시스템이 장기적으로 훨씬 이득이라는 점입니다. PBS는 이런 면에서 훌륭한 해결책을 제공해주더군요.

    Proxmox Backup Server 대시보드: 백업 성공률 및 데이터스토어 상태

    Proxmox Backup Server 대시보드에서 백업 성공률과 데이터스토어 상태를 한눈에 확인할 수 있는 스크린샷입니다.

    마무리: 나에게 맞는 백업 전략 찾기

    지금까지 Proxmox Backup Server (PBS)와 스크립트 백업의 장단점, 그리고 비용 효율성을 제 경험을 바탕으로 비교해봤습니다. 어떤 방식이 ‘절대적으로 좋다’고 단정하기는 어렵습니다. 홈랩 환경은 저마다 다르니까요.

    • 나는 최소한의 비용으로 바로 백업을 시작하고 싶다!
      : 기존에 여분의 저장 장치나 NAS가 있고, 스크립트 작성 및 관리에 익숙하시다면 스크립트 백업도 좋은 시작이 될 수 있습니다. 하지만 장기적인 관리 비용과 데이터 무결성에는 더 많은 노력을 기울여야 할 거예요.
    • 나는 백업에 시간을 많이 쓰고 싶지 않다. 안정적이고 효율적인 솔루션을 원한다!
      : PBS는 초기 설치에 약간의 리소스가 필요하지만, 일단 구축하고 나면 백업 관리의 대부분을 자동화해주고, 저장 공간을 효율적으로 사용하며, 강력한 데이터 무결성 검사 기능을 제공합니다. 장기적인 관점에서 Proxmox Backup Server 비용은 시간과 노력 측면에서 훨씬 합리적입니다.

    결론적으로 저는 PBS를 강력하게 추천합니다. 특히 홈랩에서 여러 VM과 LXC를 운영하며 VM 백업의 중요성을 느끼고 계시다면, PBS는 여러분의 소중한 데이터를 지켜주는 든든한 파트너가 될 것입니다. 🎉

    다음 글에서는 PBS를 처음 설치하고 Proxmox VE와 연동하는 구체적인 방법에 대해 다뤄볼 예정입니다. 기대해주세요!

  • [k8s] GKE WireGuard 네트워크 장애: 디버깅 및 해결 사례 연구

    [k8s] GKE WireGuard 네트워크 장애: 디버깅 및 해결 사례 연구

    [k8s] GKE WireGuard 네트워크 장애: 디버깅 및 해결 사례 연구

    안녕하세요, 13년차 서버실 지킴이입니다. 오늘은 제가 최근 GKE (Google Kubernetes Engine) 환경에서 WireGuard를 쓰다가 겪었던 네트워크 장애 경험과, 그걸 해결하기 위해 삽질했던 과정을 솔직하게 공유해볼게요. 😅 아마 인프라 엔지니어 분들이라면 누구나 한 번쯤은 복잡한 네트워크 문제로 밤샘 디버깅을 해본 경험이 있으실 거더라고요. 특히 쿠버네티스(Kubernetes) 같은 동적인 환경에서는 예측 불가능한 변수가 많아 정말 골치 아플 때가 많습니다. 저도 이번에 제대로 당했는데, 결국 해결하고 나니 또 하나 배우는 게 있네요. 💡

    이번 글에서는 GKE에서 WireGuard를 운영하면서 발생했던 특정 네트워크 통신 문제를 어떻게 발견하고, 어떤 도구들을 사용해서 원인을 분석했으며, 최종적으로 어떤 방법으로 해결했는지 자세히 이야기해 드릴게요. 혹시 비슷한 문제로 고민하고 계신 분들에게 작은 도움이 되었으면 좋겠습니다.

    GKE 클러스터와 WireGuard VPN 터널이 연결된 전체 아키텍처의 개념도입니다.

    GKE와 WireGuard, 왜 함께 쓰려 했을까요?

    먼저, 왜 제가 GKE 클러스터에 WireGuard를 도입하려고 했는지부터 말씀드려야겠네요. 사실 GKE 자체적으로도 훌륭한 네트워크 기능들을 제공합니다. VPC Native 클러스터는 Private IP를 사용하고, Cloud VPN이나 Interconnect를 통해 온프레미스(On-Premise) 환경과도 쉽게 연결할 수 있거든요. 그럼에도 불구하고 제가 WireGuard를 선택한 이유는 크게 두 가지였습니다.

    • 성능과 간결함 (Performance & Simplicity): WireGuard는 다른 VPN 솔루션들에 비해 오버헤드(Overhead)가 정말 적고, 설정도 간결하더라고요. 홈랩에서 다양한 테스트를 해봤는데 성능이 정말 만족스러웠거든요. 복잡한 IPsec 설정에 비하면 정말 ‘혁명’ 같았습니다.
    • 특정 서비스의 보안 강화 및 멀티 클러스터 네트워킹: 특정 마이크로서비스(Microservice) 간의 통신을 더욱 안전하게 암호화하고, 나아가 다른 클라우드 환경이나 온프레미스에 있는 또 다른 쿠버네티스 클러스터와 안전하게 연결하고 싶었습니다. GKE의 기본 네트워킹을 보완하는 개념으로 접근한 거죠.

    쉽게 말해, GKE의 기본 네트워크 인프라는 유지하되, 그 위에 특정 트래픽에 대해서만 WireGuard 터널(Tunnel)을 만들어서 보안과 유연성을 동시에 잡으려는 시도였습니다. 🚀

    GKE에 WireGuard 실전 구현 (그리고 문제의 시작)

    GKE에 WireGuard를 배포하는 방법은 여러 가지가 있겠지만, 저는 각 노드(Node)에 WireGuard 인터페이스를 생성하고 설정을 유지하기 위해 DaemonSet을 활용했습니다. DaemonSet은 모든 노드에 파드(Pod)를 하나씩 배포해주니까, WireGuard를 인프라 레벨에서 관리하기에 딱 맞겠다 싶었거든요.

    간단한 흐름은 이렇습니다.

    1. WireGuard 커널 모듈이 설치된 베이스 이미지 준비 (또는 initContainer 활용).
    2. 각 노드의 파드에서 WireGuard 인터페이스(wg0) 생성 및 설정.
    3. 다른 피어(Peer)들과의 연결 설정 (PublicKey, Endpoint, AllowedIPs).
    4. 필요한 라우팅 테이블(Routing Table) 및 iptables 규칙 추가.

    초기 배포는 나름 순조로웠습니다. DaemonSet으로 WireGuard 파드를 띄우고, 각 노드에 wg0 인터페이스가 잘 생성되는 것을 확인했거든요. kubectl exec -it [wireguard-pod] -- wg show 명령어로 상태를 확인해보니 피어들과의 핸드셰이크(Handshake)도 정상적으로 이루어지는 것처럼 보였어요. 🎉

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: wireguard-node
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          app: wireguard-node
      template:
        metadata:
          labels:
            app: wireguard-node
        spec:
          hostNetwork: true # 노드 네트워크 직접 사용
          hostPID: true # 프로세스 네임스페이스 공유
          containers:
          - name: wireguard
            image: <your-wireguard-image>
            securityContext:
              privileged: true # 특권 모드 활성화
              capabilities:
                add:
                - NET_ADMIN
                - SYS_MODULE
            volumeMounts:
            - name: lib-modules
              mountPath: /lib/modules
              readOnly: true
            - name: wg-config
              mountPath: /etc/wireguard
            command: ["sh", "-c"]
            args: 
              - |-
                # WireGuard 커널 모듈 로드
                modprobe wireguard
                # WireGuard 인터페이스 및 라우팅 설정 스크립트 실행
                /usr/local/bin/setup_wireguard.sh
          volumes:
          - name: lib-modules
            hostPath:
              path: /lib/modules
          - name: wg-config
            configMap:
              name: wireguard-config
              items:
              - key: wg0.conf
                path: wg0.conf
    

    이렇게 설정하고, ConfigMap에 각 노드의 WireGuard 설정 파일(wg0.conf)을 넣어서 배포했습니다. 초기에는 내부 서비스 간 통신이나 외부 WireGuard 피어와의 통신도 잘 되는 듯했어요. 그런데….

    GKE DaemonSet을 이용한 WireGuard 설정 YAML과 WireGuard `wg0.conf` 파일 예시

    WireGuard 설정을 위한 DaemonSet YAML과 wg0.conf 파일의 구성 예시입니다.

    ⚠️ 삽질의 시작: 네트워크 장애 발생 및 쿠버네티스 트러블슈팅

    문제는 GKE 노드가 재시작되거나, 특정 네트워크 이벤트를 겪은 후에 발생했습니다. 갑자기 WireGuard 터널을 통해 통신해야 하는 파드들이 서로 연결되지 않는 현상이 나타나기 시작한 겁니다. 처음엔 ‘이게 뭔가?’ 싶었죠. 🤯

    증상

    • WireGuard 터널을 사용하는 파드(Pod) 간의 통신 불능.
    • wg show 명령으로는 터널이 up 상태이고 피어들도 연결된 것처럼 보임.
    • 하지만 ping이나 curl 같은 기본적인 네트워크 명령어조차 실패.

    디버깅 과정

    저는 다음과 같은 단계로 디버깅을 시작했습니다.

    1. wg show 확인: 가장 먼저 WireGuard 자체의 상태를 확인했습니다. 아까 말씀드렸듯이, 터널은 정상적으로 보였거든요. latest handshake 시간도 최근으로 업데이트되고 있었고요.
    2. ip a, ip route 확인: WireGuard 인터페이스(wg0)가 정상적으로 IP를 가지고 있는지, 그리고 WireGuard 서브넷(Subnet)으로 가는 라우팅 테이블이 제대로 설정되어 있는지 확인했습니다. 여기서 이상한 점을 발견했습니다. 특정 노드에서는 WireGuard 서브넷으로 가는 라우팅 규칙이 사라져 있거나, GKE의 자체 네트워킹과 충돌하는 듯한 규칙이 혼재되어 있었습니다.
    3. iptables -L -n -v 확인: 라우팅 문제가 아니라 iptables 규칙 문제일 수도 있겠다 싶어서 확인해봤거든요. GKE는 자체적으로 복잡한 iptables 규칙들을 관리하는데, 제가 추가한 WireGuard 관련 규칙들이 제대로 적용되지 않거나, GKE의 규칙에 의해 덮어씌워지는 경우가 있었습니다. 특히 FORWARD 체인에서 문제가 발생할 가능성이 높다고 판단했어요.
    4. tcpdump 활용: 실제 패킷(Packet)이 어디까지 도달하는지 확인하기 위해 tcpdump를 사용했습니다. WireGuard 인터페이스(wg0)와 물리 인터페이스(eth0 등)에서 동시에 패킷을 캡처해보니, 파드에서 WireGuard 서브넷으로 나가는 패킷은 wg0으로 들어오지만, 실제 암호화되어 외부로 나가는 트래픽이 없거나, 혹은 돌아오는 응답이 중간에 사라지는 것을 확인했습니다.
    5. GKE 노드 재시작 테스트: 가장 결정적인 단서는 GKE 노드를 재시작할 때마다 문제가 발생한다는 것이었어요. 노드가 재시작되면 WireGuard DaemonSet 파드도 다시 시작되지만, 그 과정에서 네트워크 설정의 영속성(Persistence)이 깨지는 것이 분명했거든요.

    원인 분석: GKE의 자체 네트워킹과 WireGuard의 미묘한 충돌

    결론적으로 원인은 GKE의 자체 네트워킹 시스템과 WireGuard의 라우팅 및 iptables 설정이 충돌하거나, 혹은 부팅 시점의 Race Condition 때문이라는 것을 알게 되었습니다. GKE는 각 노드에 파드 IP를 할당하고, 복잡한 라우팅과 iptables 규칙을 관리합니다. 여기에 WireGuard가 별도의 터널 인터페이스를 만들고 라우팅 규칙을 추가하면서, 특정 상황에서 GKE의 기존 규칙이 WireGuard 규칙을 덮어쓰거나, WireGuard 규칙이 GKE 트래픽을 예상치 못한 곳으로 보내버리는 문제가 발생했던 거였거든요.

    특히 노드 재시작 시, GKE의 네트워킹이 먼저 설정을 완료하고 나서 WireGuard DaemonSet이 동작하면서, WireGuard가 추가하는 규칙들이 제대로 자리 잡지 못하는 경우가 있었습니다. 😩

    ✅ 해결책: 네트워크 설정의 영속성 확보

    이 문제를 해결하기 위해 여러 방법을 시도해봤는데, 가장 효과적이었던 방법은 네트워크 설정의 영속성을 강화하고, WireGuard 설정 스크립트가 GKE의 네트워킹 초기화 이후에 안정적으로 실행되도록 하는 것이었어요.

    1. PostUp/PostDown 스크립트 활용 및 영속성 강화

    WireGuard는 wg0.conf 파일 내에 PostUp 및 PostDown 명령어를 정의할 수 있습니다. 저는 여기에 필요한 라우팅 규칙과 iptables 규칙을 명시적으로 추가하고, wg-quick up wg0 명령어를 통해 이 스크립트들이 실행되도록 했습니다. DaemonSet의 command 섹션에서 이 부분을 좀 더 견고하게 만들었거든요.

    # /usr/local/bin/setup_wireguard.sh 내용 예시
    
    #!/bin/bash
    
    # WireGuard 커널 모듈 로드
    modprobe wireguard
    
    # GKE CNI 초기화를 위해 잠시 대기 (노드마다 다를 수 있음)
    sleep 10
    
    # /etc/wireguard/wg0.conf 파일에 PostUp/PostDown 설정 포함
    # 예시: PostUp = ip route add 10.10.0.0/16 dev wg0; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
    
    # WireGuard 인터페이스 활성화
    wg-quick up wg0
    
    # 설정이 유실되지 않도록 주기적으로 모니터링
    while true; do
      sleep 300
      # 필요시 wg0 상태 체크 및 재설정 로직
    done
    

    또한, WireGuard DaemonSet 파드가 시작될 때마다 이 setup_wireguard.sh 스크립트가 실행되도록 하고, 스크립트 내부에서 GKE 네트워킹이 완전히 준비될 때까지 일정 시간 대기하는 로직을 추가했습니다.

    2. AllowedIPs 정확한 설정

    wg0.conf 파일의 각 피어(Peer)에 대한 AllowedIPs 설정을 더욱 정확하게 지정했어요. 예를 들어, 특정 피어의 WireGuard IP만 허용하는 것이 아니라, 해당 피어 뒤에 있는 서브넷 전체를 AllowedIPs에 포함시켜 라우팅이 명확하게 이루어지도록 했습니다. 이건 WireGuard가 패킷을 어디로 포워딩할지 결정하는 정말 중요한 요소거든요.

    [Peer]
    PublicKey = <peer-public-key>
    Endpoint = <peer-endpoint>:51820
    AllowedIPs = 10.10.0.0/16, 192.168.10.0/24 # 정확한 서브넷 명시
    PersistentKeepalive = 25
    

    이 두 가지 방법을 적용하고 GKE 노드를 재부팅해보니, 드디어 문제가 해결되었습니다! 🎉 재부팅 후에도 WireGuard 터널을 통한 통신이 정상적으로 이루어졌고, 파드 간 연결도 원활했습니다. 정말이지 며칠 밤낮으로 씨름했던 문제가 해결되니 얼마나 기뻤는지 모릅니다.

    WireGuard 터널의 정상 작동을 확인하는 `wg show` 명령어 출력 및 네트워크 트래픽 모니터링 그래프

    WireGuard 터널의 정상 작동을 확인하는 wg show 명령어 출력과 정상적인 네트워크 트래픽 그래프입니다.

    마무리하며: GKE와 커스텀 네트워크 솔루션 통합 시 교훈

    이번 GKE WireGuard 네트워크 장애 해결 사례를 통해 제가 얻은 교훈은 다음과 같습니다.

    1. 관리형 서비스와 커스텀 솔루션의 경계 이해: GKE 같은 관리형 쿠버네티스 서비스는 자체적인 네트워크 관리 로직을 가지고 있습니다. 여기에 WireGuard 같은 커스텀 네트워크 솔루션을 통합할 때는 GKE의 기본 네트워킹 동작 방식을 정확히 이해하고, 충돌이 발생하지 않도록 주의해야 합니다. 특히 라우팅 테이블과 iptables 규칙은 가장 민감한 부분이거든요.
    2. 네트워크 설정의 영속성 확보: 쿠버네티스 노드는 언제든 재시작될 수 있습니다. 이때 수동으로 설정했던 네트워크 규칙들이 유실되지 않도록 DaemonSet의 command나 initContainer를 통해 영속적인 스크립트 실행 환경을 구축하는 것이 정말 중요합니다.
    3. 꼼꼼한 네트워크 디버깅 도구 활용: ip route, iptables, tcpdump, wg show 등 기본적인 네트워크 디버깅 도구들은 아무리 강조해도 지나치지 않습니다. 눈에 보이는 문제가 아니라, 실제 패킷의 흐름을 추적하는 것이 문제 해결의 핵심이거든요.
    4. 문서화 및 철저한 테스트: 복잡한 네트워크 설정을 적용할 때는 반드시 상세한 문서화를 해두고, 노드 재시작 등 다양한 시나리오에서 충분한 테스트를 거쳐야 합니다. 저도 이번에 테스트 시나리오를 좀 더 촘촘히 짰어야 했는데, 초기 검증이 미흡했던 점이 아쉬웠어요.

    GKE 운영 환경에서 커스텀 네트워크 솔루션을 도입하는 것은 분명 도전적인 일이지만, 잘만 활용하면 서비스의 유연성과 보안을 크게 향상시킬 수 있습니다. 이번 삽질 경험이 여러분의 GKE 운영에 작은 도움이 되기를 바라며, 다음번에는 또 다른 홈랩 삽질기를 들고 찾아오겠습니다! 😊

    GKE WireGuard 통합 시 고려해야 할 중요 체크리스트 인포그래픽

    GKE와 WireGuard를 통합할 때 고려해야 할 핵심 사항들을 요약한 체크리스트 인포그래픽입니다.

  • [Game] Heroic Games Launcher, PC 게임 라이브러리를 한곳에 통합하는 방법

    [Game] Heroic Games Launcher, PC 게임 라이브러리를 한곳에 통합하는 방법

    안녕하세요, 13년차 서버실 지킴이입니다. 요즘은 서버실을 지키는 것만큼이나 제 홈랩(Home Lab)에서 이것저것 만져보는 재미에 푹 빠져 살고 있는데요. 특히 게임 관련해서는 할 이야기가 정말 많습니다. 스팀(Steam)이야 워낙 독보적이라 다들 잘 쓰시지만, Epic Games Store나 GOG(Good Old Games)처럼 다른 플랫폼들도 정말 많지 않습니까? 덕분에 제 PC에는 런처(Launcher)만 서너 개가 깔려있더군요. 매번 다른 런처를 켜는 것도 일이고, 어떤 게임이 어디에 있는지 헷갈리기도 하고요. 🤦‍♂️

    그러다 문득 이런 생각이 들었습니다. ‘이걸 한곳에서 관리할 수 있으면 얼마나 좋을까?’ 스팀처럼 모든 게임을 한 런처에서 관리하고 싶은 마음, 다들 공감하시죠? 저도 처음엔 불가능하다고 생각했어요. 각 플랫폼이 독자적인 생태계를 가지고 있으니 당연히 개별 런처를 써야 한다고요. 하지만 역시 삽질은 배신하지 않습니다! 이리저리 찾아보고 직접 써보면서 정말 괜찮은 대안을 발견했거든요. 바로 오늘 소개해 드릴 Heroic Games Launcher(히로익 게임즈 런처)입니다. 🎉

    파편화된 PC 게임 라이브러리를 Heroic Games Launcher로 통합하는 개념 다이어그램

    파편화된 게임 라이브러리 관리에 지치셨다면, Heroic Games Launcher가 하나의 허브 역할을 해줄 수 있습니다.

    Heroic Games Launcher, 이게 대체 뭔가요?

    Heroic Games Launcher는 쉽게 말해 Epic Games Store와 GOG의 게임들을 한곳에서 관리하고 실행해주는 오픈소스 게임 런처거든요. 스팀처럼 자체 게임을 파는 플랫폼은 아니고, 기존 플랫폼의 게임들을 대신 실행시켜주는 일종의 프론트엔드(Frontend) 역할을 한다고 보시면 됩니다. 특히 리눅스(Linux) 사용자들에게는 Wine(와인)이나 Proton(프로톤)과의 연동 덕분에 Windows 게임을 리눅스에서도 쉽게 즐길 수 있게 해주는 정말 고마운 존재예요.

    왜 Heroic Games Launcher가 필요할까요?

    • 파편화된 라이브러리 통합: Epic, GOG 게임을 한곳에서 관리할 수 있어서, 어떤 게임이 어디에 있는지 헤매지 않아도 되죠.
    • 리눅스 지원: 공식 런처는 리눅스를 지원하지 않지만, Heroic Games Launcher는 리눅스에서도 완벽하게 작동합니다. 저처럼 홈랩에서 리눅스 머신을 운영하면서 게임도 하고 싶은 분들에게는 필수 도구거든요.
    • 간편한 게임 관리: 설치, 업데이트, 삭제는 물론 Wine/Proton 버전 관리까지 깔끔하게 처리해줍니다.
    • 다양한 기능: 세이브 파일 동기화, 모드(Mod) 설치, 게임 설정 변경 등 공식 런처에서는 제공하지 않거나 복잡했던 기능들을 훨씬 쉽게 쓸 수 있어요.

    삽질 끝에 찾은 실전 구현: Heroic Games Launcher 설치 및 사용법

    자, 그럼 이제 Heroic Games Launcher를 직접 설치하고 사용해보는 시간을 가져볼까요? 저는 주로 리눅스 환경에서 많이 사용하지만, Windows나 macOS에서도 설치 방법은 크게 다르지 않습니다. 여기서는 가장 일반적인 방법들을 소개해 드릴게요.

    1단계: Heroic Games Launcher 다운로드 및 설치

    Heroic Games Launcher는 다양한 운영체제를 지원합니다. 자신의 OS에 맞는 설치 파일을 받으면 되거든요.

    Windows 및 macOS

    1. Heroic Games Launcher 공식 웹사이트에 접속합니다.
    2. 자신의 운영체제에 맞는 설치 파일(<code>.exe, .dmg)을 다운로드 받습니다.
    3. 다운로드 받은 파일을 실행하여 일반적인 프로그램 설치 과정대로 진행하면 됩니다.

    Linux (저는 주로 Flatpak을 이용합니다)

    리눅스 환경에서는 Flatpak을 이용하는 게 가장 쉽고 권장되는 방법이에요. 만약 Flatpak이 설치되어 있지 않다면 먼저 설치해야 합니다.

    # Flatpak 설치 (예시: Ubuntu/Debian 기반)
    sudo apt install flatpak
    sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
    
    # Heroic Games Launcher 설치
    flatpak install flathub com.heroicgameslauncher.hgl
    

    설치가 완료되면 애플리케이션 메뉴에서 ‘Heroic Games Launcher’를 찾아 실행할 수 있습니다. 처음 실행하면 약간의 초기 설정 과정이 있을 수 있더라고요.

    Heroic Games Launcher의 깔끔한 게임 라이브러리 인터페이스 스크린샷

    Heroic Games Launcher의 깔끔하고 직관적인 UI. Epic Games와 GOG 게임들이 한눈에 보입니다.

    2단계: 계정 연동 및 라이브러리 가져오기

    Heroic Games Launcher를 실행하면 가장 먼저 Epic Games와 GOG 계정을 연동하라는 메시지가 나타나요. 각 플랫폼의 로그인 버튼을 클릭하고 웹 브라우저를 통해 로그인하면 됩니다.

    1. Heroic Games Launcher 좌측 메뉴에서 ‘Stores’ 섹션으로 이동합니다.
    2. ‘Epic Games’ 또는 ‘GOG’ 버튼을 클릭하여 웹 로그인 과정을 진행합니다.
    3. 로그인이 성공적으로 완료되면, 해당 플랫폼의 게임 라이브러리가 Heroic Games Launcher에 자동으로 동기화됩니다.

    이 과정에서 2단계 인증(2FA)을 사용하고 있다면, 인증 코드를 입력해야 할 수 있어요. 저도 이 부분에서 처음엔 좀 헤맸는데, 웹 브라우저에서 제대로 로그인되었는지 확인하고 Heroic 앱으로 돌아오면 대부분 해결되더라고요. 💡

    3단계: 게임 설치 및 실행

    라이브러리가 동기화되었다면, 이제 원하는 게임을 설치하고 실행할 수 있습니다.

    1. 좌측 메뉴에서 ‘Library’를 선택합니다.
    2. 설치하고 싶은 게임을 선택한 후 ‘Install’ 버튼을 클릭합니다. 설치 경로 등을 설정할 수 있어요.
    3. 설치가 완료되면 ‘Play’ 버튼을 클릭하여 게임을 실행하면 됩니다.

    리눅스 사용자라면, 게임 설치 시 Wine 또는 Proton 버전을 선택해야 합니다. Heroic Games Launcher는 자체적으로 다양한 Wine/Proton 버전을 관리하고 다운로드할 수 있는 기능을 제공하거든요. 최신 버전이나 특정 게임에 잘 맞는 버전을 선택하는 게 중요합니다. 저 같은 경우, 특정 게임이 안 돌아갈 때 여러 Proton 버전을 바꿔가면서 시도해봤는데, 결국 맞는 버전을 찾아서 성공한 경험이 많더라고요. 😅

    ⚠️ 주의사항 및 트러블슈팅 (삽질 경험 공유)

    Heroic Games Launcher가 아무리 편리해도 만능은 아닙니다. 저도 사용하면서 몇 가지 삽질을 좀 했거든요. 여러분은 저 같은 고생을 덜 하시라고 몇 가지 팁을 공유합니다.

    • 로그인 문제 (특히 2FA): 웹 브라우저를 통해 로그인할 때 간혹 세션이 제대로 넘어오지 않는 경우가 있어요. 이럴 때는 Heroic 앱을 완전히 종료하고 다시 실행하거나, 웹 브라우저에서 직접 Epic/GOG 계정 페이지에 로그인해서 세션을 활성화한 후 Heroic에서 다시 시도해 보세요. 제 경험상 ‘로그인 오류’ 메시지가 뜰 때는 대부분 이 문제더라고요.
    • 게임 실행 문제: 특정 게임은 Heroic Games Launcher에서 바로 실행되지 않을 수 있습니다.
      • 리눅스 환경: 앞서 말했듯이 Wine/Proton 버전을 바꿔보는 게 가장 중요합니다. GE-Proton 같은 커스텀 Proton 버전이 특정 게임에서 더 좋은 성능을 보여주기도 하거든요. Heroic 설정에서 Wine Manager를 통해 다양한 버전을 설치하고 시도해볼 수 있습니다.
      • Windows 환경: 드물지만 게임의 실행 파일 경로나 종속성(Dependencies) 문제일 수 있어요. Heroic의 게임 설정에서 실행 파일 경로가 올바른지 확인하고, 필요한 경우 DirectX나 Visual C++ 재배포 패키지 등을 수동으로 설치해야 할 수도 있습니다.
    • 성능 문제: Heroic 자체가 성능에 큰 영향을 주지는 않지만, 특히 리눅스에서 Wine/Proton을 통해 게임을 실행할 때는 Windows 환경보다 성능이 약간 떨어질 수 있어요. 최신 그래픽 드라이버를 사용하고, 게임 설정을 최적화하는 것이 중요합니다.
    Heroic Games Launcher를 통해 성공적으로 실행된 PC 게임 화면

    삽질 끝에 Heroic Games Launcher로 실행된 게임 화면. 이제 여러 런처를 오갈 필요 없이 편하게 게임을 즐길 수 있습니다. 🎉

    검증 및 결과: 드디어 통합된 게임 라이브러리!

    이 모든 과정을 거치고 나면, 드디어 여러분의 Heroic Games Launcher에는 Epic Games와 GOG의 게임들이 한데 모여 있는 것을 보실 수 있을 겁니다. 제가 직접 사용해보니, 게임을 시작하기 위해 여러 런처를 켰다 껐다 할 필요 없이 Heroic 하나만 실행하면 되니까 정말 편하더라고요. 특히 리눅스에서 Windows 게임을 이렇게 쉽게 즐길 수 있을 줄은 몰랐어요.

    물론 아직 Steam 게임까지 통합할 수는 없지만, Epic Games Store와 GOG 라이브러리만 해도 상당한 비중을 차지하거든요. 이들의 통합만으로도 게임 관리의 번거로움이 크게 줄어듭니다. 저처럼 홈랩에서 리눅스 게이밍 환경을 구축하고 싶었지만 어려움을 겪었던 분들에게는 정말 강력 추천하는 솔루션입니다.

    Heroic Games Launcher의 핵심 기능과 장점을 요약한 인포그래픽

    Heroic Games Launcher가 제공하는 주요 기능과 장점을 한눈에 보여주는 요약 인포그래픽.

    마무리하며: 또 다른 삽질을 위한 준비

    오늘은 Heroic Games Launcher를 통해 파편화된 PC 게임 라이브러리를 통합하는 방법에 대해 이야기해봤습니다. 제가 직접 겪었던 삽질 경험들을 바탕으로 최대한 쉽게 설명해 드리고자 노력했는데, 도움이 되셨기를 바랍니다. 기술 블로그를 운영하면서 느끼는 거지만, 결국 새로운 기술을 익히고 문제를 해결하는 과정은 끊임없는 삽질의 연속이더군요. 😅

    Heroic Games Launcher는 단순한 게임 런처를 넘어, 오픈소스 생태계가 개인 사용자들에게 얼마나 큰 자유와 편의를 제공할 수 있는지 보여주는 좋은 예시라고 생각합니다. 다음번에는 이런 통합 런처들을 Steam Deck 같은 휴대용 기기에서 어떻게 활용할 수 있을지에 대한 경험담을 풀어볼까 합니다. 긴 글 읽어주셔서 감사합니다! 궁금한 점이 있다면 언제든 댓글 남겨주세요. 저도 함께 고민하고 답을 찾아보겠습니다. 그럼 다음 글에서 또 만나요! 👋

  • [Kubernetes] Cilium CNI 성능 벤치마크: Calico, Flannel과 직접 비교

    [Kubernetes] Cilium CNI 성능 벤치마크: Calico, Flannel과 직접 비교

    [Kubernetes] Cilium CNI 성능 벤치마크: Calico, Flannel과 직접 비교

    안녕하세요, 13년차 서버실 지킴이입니다. 오늘은 Kubernetes(쿠버네티스) 환경에서 가장 중요한 요소 중 하나인 CNI(Container Network Interface, 컨테이너 네트워크 인터페이스) 솔루션들의 성능을 제가 직접 벤치마크해본 경험을 공유하려고 해요. 특히 요즘 핫한 Cilium(실리움)이 기존의 Calico(칼리코), Flannel(플라넬)과 비교해서 얼마나 뛰어난지 궁금했거든요.

    인프라 엔지니어로 일하다 보면 ‘네트워크 성능이 왜 이렇게 느리지?’ 하는 답답함을 겪을 때가 많습니다. 특히 마이크로서비스 아키텍처에서는 Pod(파드) 간의 통신이 엄청나게 빈번하게 일어나기 때문에, CNI의 선택이 전체 애플리케이션 성능에 결정적인 영향을 미치죠. 저도 홈랩에서 이것저것 실험해보면서 이 문제로 삽질을 좀 했거든요. 그래서 이번 기회에 주요 CNI 솔루션들을 직접 비교해보면서 그 차이를 피부로 느껴보고 싶었습니다.

    CNI란 뭐고 어떤 종류가 있을까?

    먼저 CNI가 뭔지 간단하게 짚고 넘어갈게요. CNI는 컨테이너 런타임과 네트워크 플러그인 간의 표준 인터페이스를 정의한 규약입니다. 쉽게 말해, Kubernetes Pod들이 어떻게 서로 통신하고 외부와 연결될지 결정하는 ‘네트워크 길잡이’ 역할을 하는 거죠.

    • Flannel (플라넬): 가장 단순하고 설치가 쉬운 CNI 중 하나입니다. 주로 Overlay Network(오버레이 네트워크) 방식인 VXLAN(Virtual Extensible LAN)을 사용해요. 설정이 간단해서 초보자들이나 소규모 클러스터에서 많이 선택하지만, 성능 오버헤드가 좀 있는 편입니다.
    • Calico (칼리코): 네트워크 정책(Network Policy) 기능이 강력하고 성능도 준수해서 많은 프로덕션 환경에서 사용됩니다. IP-in-IP 터널링이나 BGP(Border Gateway Protocol) 라우팅 방식을 주로 쓰는데, 특히 BGP 모드에서는 오버헤드가 적어서 좋은 성능을 보여주죠. 보안 기능도 뛰어나고요.
    • Cilium (실리움): 오늘 주인공이죠! eBPF(extended Berkeley Packet Filter, 확장된 버클리 패킷 필터)라는 기술을 기반으로 합니다. eBPF는 리눅스 커널 내부에서 프로그램을 실행할 수 있게 해주는 기술인데, 이걸 활용해서 Cilium은 컨테이너 네트워크 트래픽을 커널 레벨에서 직접 처리합니다. 이 덕분에 기존 CNI들이 가졌던 성능 오버헤드를 크게 줄이고, 더 세밀한 네트워크 정책과 가시성(Observability)을 제공할 수 있게 되는 거예요. 처음엔 이게 뭔가 싶었는데, 써보니 진짜 매력적이더라고요.
    Flannel, Calico, Cilium CNI 솔루션의 네트워크 아키텍처 비교 다이어그램

    이 이미지는 Flannel, Calico, Cilium 각 CNI 솔루션의 네트워크 아키텍처를 시각적으로 비교하여, 데이터 플레인 처리 방식의 차이를 보여줍니다.

    실전 구현: 벤치마크 환경 준비와 테스트 방법

    자, 그럼 이제 제가 어떻게 벤치마크를 진행했는지 공유해볼게요. 홈랩에 Kubernetes 클러스터를 kubeadm으로 구성했고, 각 CNI를 순서대로 설치해가며 성능을 측정했습니다.

    1. Cilium CNI 벤치마크를 위한 환경 준비

    저는 3노드(마스터 1, 워커 2) Kubernetes 클러스터를 사용했습니다. 테스트의 공정성을 위해 각 CNI를 설치하기 전에는 항상 클러스터를 초기화하고 깨끗한 상태에서 시작했어요. 벤치마크 도구로는 네트워크 성능 측정에 널리 사용되는 netperf를 선택했습니다. TCP_STREAM(대역폭), TCP_RR(요청/응답 지연 시간) 두 가지 모드로 측정했어요.

    
    # netperf 설치 (Ubuntu 기준)
    sudo apt update
    sudo apt install netperf -y
    
    # 벤치마크용 Pod 배포 예시
    kubectl apply -f - <

    각 CNI를 설치한 후, netperf-server Pod를 배포하고 다른 Pod에서 netperf 클라이언트를 실행하여 서버 Pod로 트래픽을 보냈습니다. Pod-to-Pod 통신과 Pod-to-Service 통신 두 가지 시나리오를 모두 측정했어요.

    2. Cilium 포함 각 CNI 설치 및 성능 측정

    1. Flannel 설치 및 측정:
      
      kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
      # Pod Ready 확인 후 netperf 측정
      
    2. Calico 설치 및 측정:
      
      kubectl apply -f https://docs.tigera.io/calico/latest/manifests/calico.yaml
      # Pod Ready 확인 후 netperf 측정
      
    3. Cilium 설치 및 성능 측정:
      
      helm repo add cilium https://helm.cilium.io/
      helm install cilium cilium/cilium --version 1.15.5 \
        --namespace kube-system \
        --set ipam.mode=kubernetes \
        --set tunnel=vxlan \
        --set egressGateway.enabled=true # 예시 설정
      # Pod Ready 확인 후 netperf 측정
      

    ⚠️ 주의사항: 각 CNI를 설치하기 전에 기존 CNI를 완전히 삭제하고 클러스터를 초기화하거나, CNI 관련 리소스를 제거해야 합니다. 그렇지 않으면 네트워크 충돌로 Pod들이 정상적으로 시작되지 않을 수 있거든요. 제가 처음엔 이걸 놓쳐서 Pod들이 Pending(대기) 상태에서 벗어나지 못하는 삽질을 좀 했습니다 ㅎㅎ.

    이 이미지는 Kubernetes 클러스터에 Cilium CNI를 helm을 이용하여 설치하는 과정을 보여주는 터미널 스크린샷입니다.

    ⚠️ 삽질 경험과 Cilium 트러블슈팅

    솔직히 말씀드리면, Cilium을 처음 설치할 때 좀 애먹었습니다. kubeadm으로 구성한 클러스터에서 Cilium Pod들이 CrashLoopBackOff(크래시 루프백 오프) 상태에 빠지더라고요. 확인해보니 커널 버전 문제와 eBPF 관련 의존성 설정이 제대로 안 된 경우였습니다. Cilium은 eBPF 기반이라 리눅스 커널 버전이 어느 정도 이상이어야 하고, 특정 커널 모듈이나 설정이 활성화되어 있어야 하거든요. 예를 들어, CONFIG_BPF_JIT 같은 커널 옵션이 활성화되어 있는지 확인해야 합니다.

    이런 문제 때문에 Cilium 설치 전에 공식 문서를 꼼꼼히 읽어보고, cilium preflight check 같은 명령어로 환경을 미리 점검하는 게 정말 중요합니다. 덕분에 커널 컴파일 옵션까지 찾아보는 등 깊은 공부를 하게 됐네요. 역시 삽질은 최고의 공부 방법입니다!

    검증 결과: Cilium CNI의 성능은 정말 압도적일까?

    수많은 테스트와 삽질 끝에 얻은 결과는 예상대로였습니다. Cilium이 Calico, Flannel 대비 전반적으로 더 우수한 네트워크 성능을 보여줬거든요.

    • Throughput (대역폭): 특히 대량의 데이터를 전송하는 TCP_STREAM 테스트에서 Cilium은 Calico나 Flannel보다 더 높은 처리량을 기록했습니다. eBPF 덕분에 커널 레벨에서 패킷을 직접 처리하면서 컨텍스트 스위칭(Context Switching) 오버헤드가 크게 줄어든 거 같아요.
    • Latency (지연 시간): 요청-응답(TCP_RR) 테스트에서도 Cilium이 가장 낮은 지연 시간을 보여줬습니다. 이는 마이크로서비스 간의 빈번한 API 호출에 있어 정말 중요한 이점이거든요. 애플리케이션의 반응성이 훨씬 좋아지는 거죠.

    물론, 테스트 환경이나 네트워크 구성에 따라 결과는 달라질 수 있습니다. 하지만 제 홈랩 환경에서는 Cilium의 성능 향상이 눈에 띄게 확인되었어요. 특히 Pod 간의 통신이 잦은 환경이라면 Cilium CNI의 도입을 진지하게 고려해볼 만하다고 생각합니다.

    Cilium, Calico, Flannel CNI 성능 벤치마크 결과 비교 그래프

    이 이미지는 Cilium, Calico, Flannel 각 CNI 솔루션의 네트워크 Throughput(대역폭)과 Latency(지연 시간) 벤치마크 결과를 보여주는 비교 그래프입니다.

    결론: Cilium은 미래의 CNI 표준이 될까?

    이번 벤치마크를 통해 Cilium의 강력한 성능을 직접 확인할 수 있었습니다. eBPF라는 혁신적인 기술을 기반으로 기존 CNI의 한계를 뛰어넘는 모습을 보여줬네요. 특히 고성능이 요구되는 환경이나 복잡한 네트워크 정책, 그리고 뛰어난 가시성이 필요한 곳이라면 Cilium은 정말 훌륭한 선택지가 될 겁니다.

    하지만 Cilium이 만능은 아닙니다. eBPF에 대한 이해가 필요하고, 상대적으로 커널 의존성이 높아서 환경 구성에 더 신경 써야 할 부분이 있어요. 설치와 설정도 Calico나 Flannel보다는 복잡할 수 있다는 점도 고려해야 합니다.

    결론적으로, 간단하고 빠른 배포가 우선이라면 Flannel, 안정적인 성능과 강력한 네트워크 정책이 필요하다면 Calico, 그리고 최고의 성능과 보안, 고급 가시성을 원한다면 Cilium을 고려해보시길 추천합니다. 저도 이제 프로덕션 환경에서 Cilium을 더 적극적으로 도입해볼까 고민 중입니다.

    다음번엔 Cilium의 네트워크 정책(Network Policy) 기능과 서비스 메시(Service Mesh) 연동에 대해 더 자세히 다뤄볼 예정이니 기대해주세요! 긴 글 읽어주셔서 감사합니다.

    Flannel, Calico, Cilium CNI 솔루션 장단점 및 추천 시나리오 요약 인포그래픽

    이 이미지는 Flannel, Calico, Cilium 각 CNI 솔루션의 주요 특징, 장점, 단점 및 추천 사용 시나리오를 요약 비교한 인포그래픽입니다.

  • [Cloud] GitLab CI/CD, 월 300달러 린트 비용 낭비 막는 법

    [Cloud] GitLab CI/CD, 월 300달러 린트 비용 낭비 막는 법

    안녕하세요, 13년차 인프라 엔지니어 ’13년차의 서버실’입니다. 오늘은 많은 분들이 공감하실 만한, 하지만 간과하기 쉬운 CI/CD 비용 문제에 대해 이야기해보려고 해요. 특히 GitLab CI/CD 비용 최적화와 관련해서 제가 직접 겪었던 뼈아픈 경험과 그 해결 과정을 공유합니다. 사실 저도 처음엔 CI/CD를 구축하고 나면 다 끝난 줄 알았거든요. 그런데 시간이 지나면서 예상치 못한 곳에서 비용이 새고 있더라고요. 바로 불필요하게 돌아가는 린트(Lint) 비용이었죠. 한 달에 무려 300달러나 되는 돈이 린트 때문에 나가고 있었다니, 처음엔 믿을 수가 없었어요. 오늘은 이 낭비를 어떻게 막았는지, 그 노하우를 풀어볼게요!

    GitLab CI/CD 린트 비용 낭비 및 최적화 전후 비교 다이어그램

    GitLab CI/CD 파이프라인에서 불필요한 린트(Lint) 작업으로 인해 비용이 낭비되고, 이를 최적화하여 절감하는 과정을 시각적으로 보여주는 다이어그램.

    CI/CD 린트(Lint)가 왜 비용 낭비의 주범이 될까요?

    CI/CD(Continuous Integration/Continuous Deployment, 지속적 통합/지속적 배포)는 정말 신기한 도구거든요. 코드를 푸시할 때마다 자동으로 테스트하고 배포하니까요. 이 과정에서 린트(Lint, 코드 스타일 및 잠재적 오류 검사)는 코드 품질을 유지하는 데 정말 중요한 역할을 합니다. 문제가 크기 전에 미리 잡아주니 정말 고맙죠.

    그런데 여기서 문제가 발생합니다. 대부분의 CI/CD 설정은 코드가 변경될 때마다, 즉 <code>git push 할 때마다 모든 파이프라인 작업을 실행하도록 되어 있더라고요. 작은 오타 수정이나 README 파일 업데이트 같은 사소한 변경에도 린트 작업을 포함한 모든 CI 작업이 돌아가는 거죠. 린트 작업 자체는 비교적 가볍다고 생각하기 쉽지만, 이게 수십, 수백 번 반복되면 이야기가 달라집니다. 특히 GitLab.com 같은 SaaS(Software as a Service) 환경에서는 사용량에 따라 CI/CD Runner minutes(러너 사용 시간) 비용이 발생하거든요. 제가 운영하는 홈랩에서도 처음엔 이런 비용을 크게 신경 쓰지 않았는데, 프로젝트가 많아지고 커밋이 잦아지면서 슬금슬금 비용이 올라가는 걸 보고 깜짝 놀랐습니다.

    비용 낭비의 핵심 원인:

    • 잦은 커밋: 개발 과정에서 수많은 중간 커밋이 발생합니다.
    • 불필요한 실행: 코드를 변경하지 않는 파일(예: 주석, 문서)의 변경에도 린트가 실행됩니다.
    • 모든 브랜치 실행: 개발 브랜치, 피처 브랜치 등 모든 브랜치에 푸시될 때마다 린트가 실행됩니다.

    이런 상황을 제가 직접 겪어보니, “아, 이건 뭔가 바꿔야겠다!” 싶더라고요. 그래서 CI/CD 최적화 방안을 진지하게 고민하기 시작했습니다.

    GitLab CI/CD 비용 최적화를 위한 핵심 전략: 조건부 실행 (Conditional Execution)

    GitLab CI/CD에서 비용을 절감하는 가장 효과적인 방법 중 하나는 조건부 실행(Conditional Execution)입니다. 말 그대로 특정 조건이 충족될 때만 CI/CD 작업을 실행하도록 하는 거죠. 린트 작업의 경우, 모든 커밋에 대해 실행하기보다는 특정 상황에서만 실행하도록 제한할 수 있습니다.

    제가 주로 활용한 전략은 다음과 같습니다:

    1. 머지 리퀘스트(Merge Request) 시에만 실행: 피처 브랜치에서 개발할 때는 린트 작업을 건너뛰고, 메인 브랜치로 머지하기 위한 MR이 생성될 때만 린트 검사를 실행합니다. 이렇게 하면 불필요한 중간 커밋에 대한 린트 실행을 대폭 줄일 수 있거든요.
    2. 코드 변경이 있는 파일에 대해서만 실행: 정말 필요한 경우에만 린트 작업을 실행하도록 조건을 더 세분화할 수 있습니다. 예를 들어, 특정 코드 파일이 변경되었을 때만 린트 작업을 실행하는 방식이죠.

    GitLab CI/CD는 rules 키워드를 통해 이런 조건부 실행을 강력하게 지원합니다. 처음엔 only/except 문법을 사용하기도 했는데, rules가 훨씬 유연하고 강력하더라고요. rules를 사용하면 여러 조건을 조합해서 원하는 시나리오를 만들 수 있습니다.

    실전 구현: `.gitlab-ci.yml`에 조건부 린트 잡(Job) 추가하기

    자, 그럼 이제 제가 실제로 어떻게 GitLab CI 비용 절감을 이뤄냈는지 `.gitlab-ci.yml` 설정과 함께 설명해 드릴게요. 핵심은 린트 작업을 위한 잡(Job)에 rules를 적용하는 겁니다.

    1. 머지 리퀘스트(MR) 시에만 린트 실행하기

    가장 기본적이고 효과적인 방법입니다. 개발 브랜치에 푸시할 때는 린트를 건너뛰고, MR이 생성되거나 업데이트될 때만 린트를 실행합니다. 이렇게 하면 개발 중 발생하는 수많은 중간 커밋의 CI 비용을 아낄 수 있거든요.

    
    lint_job:
      stage: lint
      image: python:3.9-slim # 린트 도구에 맞는 이미지 사용
      script:
        - pip install flake8 # 예시: Python flake8 린터 설치
        - flake8 .
      rules:
        - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' # MR이 생성되거나 업데이트될 때만 실행
          when: on_success
        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' # 기본 브랜치(master/main)에 푸시될 때 실행 (최종 검증)
          when: on_success
    

    위 코드에서 $CI_PIPELINE_SOURCE == "merge_request_event"는 머지 리퀘스트 파이프라인에서만 이 잡(Job)을 실행하라는 의미입니다. 그리고 $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH는 메인 브랜치(보통 main 또는 master)에 직접 푸시될 때도 린트가 실행되도록 해서 최종적인 코드 품질을 보장합니다. 이렇게 설정하니 월 300달러나 나가던 린트 비용이 확 줄어들더라고요! 🎉

    GitLab CI/CD 린트 조건부 실행을 위한 .gitlab-ci.yml rules 설정

    GitLab CI/CD 설정 파일(.gitlab-ci.yml)에서 ‘rules’ 키워드를 사용하여 린트(Lint) 작업을 조건부로 실행하도록 구성된 YAML 코드 스니펫.

    2. 특정 파일 변경 시에만 린트 실행하기 (고급)

    좀 더 세밀한 제어가 필요하다면 rules:changes를 활용할 수 있습니다. 예를 들어, Python 코드 파일(.py)이 변경되었을 때만 Python 린트를 실행하고, JavaScript 파일(.js)이 변경되었을 때만 JavaScript 린트를 실행하는 식이죠.

    
    python_lint_job:
      stage: lint
      image: python:3.9-slim
      script:
        - pip install flake8
        - flake8 .
      rules:
        - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
          changes:
            - "**/*.py" # .py 파일 변경 시에만 실행
          when: on_success
        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
          changes:
            - "**/*.py"
          when: on_success
    
    javascript_lint_job:
      stage: lint
      image: node:16-slim # Node.js 린터에 맞는 이미지 사용
      script:
        - npm install eslint
        - npx eslint .
      rules:
        - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
          changes:
            - "**/*.js" # .js 파일 변경 시에만 실행
          when: on_success
        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
          changes:
            - "**/*.js"
          when: on_success
    

    이 방식은 파이프라인을 더욱 효율적으로 만들지만, rules:changes는 GitLab Runner가 변경된 파일을 확인하는 과정에서 약간의 오버헤드가 발생할 수 있거든요. 하지만 특정 언어의 린트가 매우 무겁거나, 모노레포(Monorepo)처럼 여러 프로젝트가 한 레포지토리에 있을 때는 정말 유용하게 활용할 수 있습니다. 제가 홈랩에서 여러 마이크로서비스를 한 레포에 넣어두고 관리할 때 이 방법을 써봤는데, 확실히 비용 절감 효과가 좋았어요.

    ⚠️ 주의사항 및 트러블슈팅: 꼼꼼함이 핵심!

    GitLab CI/CD 최적화는 비용 절감이라는 큰 장점이 있지만, 몇 가지 주의할 점도 있습니다. 제가 삽질 좀 하면서 겪었던 시행착오들을 공유해 드릴게요.

    1. 조건 설정의 오작동: rules 문법이 생각보다 까다로울 수 있거든요. 조건을 너무 복잡하게 설정하면 예상치 못하게 잡(Job)이 실행되지 않거나, 반대로 불필요하게 실행될 수 있어요. 항상 테스트를 통해 의도한 대로 동작하는지 확인해야 합니다. rules:if와 rules:changes를 함께 사용할 때는 특히 주의해야 합니다.
    2. 개발자의 실수: 머지 리퀘스트 파이프라인에서만 린트를 실행하도록 했는데, 개발자가 실수로 로컬에서 린트를 돌리지 않고 MR을 올리는 경우가 생길 수 있거든요. 이렇게 되면 MR 파이프라인에서 린트 에러가 발생하고, 다시 수정해서 커밋해야 하는 번거로움이 생기죠. 이를 방지하기 위해 프리-커밋 훅(Pre-commit Hook) 같은 도구를 도입하여 로컬에서도 린트 검사를 강제하는 것을 고려해볼 수 있습니다. 저도 이 문제 때문에 초기에는 좀 곤란했는데, husky나 lint-staged 같은 도구를 도입해서 해결했어요.
    3. 초기 러너 비용: rules:changes를 사용할 때, GitLab Runner는 변경된 파일 목록을 가져오기 위해 Git 히스토리를 확인해야 합니다. 이 과정에서 필요한 최소한의 Git 클론(clone) 작업이 발생하므로, 아주 미미하지만 초기 러너 사용 시간이 발생할 수 있거든요. 대부분의 경우 무시할 만한 수준이지만, 극단적인 최적화를 목표로 한다면 고려할 만한 요소입니다.

    가장 중요한 건, 변경 사항을 적용한 후에 GitLab CI/CD 파이프라인을 여러 시나리오(새 브랜치 푸시, MR 생성, 메인 브랜치 푸시 등)로 테스트해보고, CI/CD Analytics(분석) 탭에서 러너 사용 시간을 주기적으로 확인하는 겁니다. 저도 처음엔 설정이 제대로 됐는지 확신이 없어서 파이프라인 로그를 꼼꼼히 뜯어봤거든요. 💡

    결과 검증: 실제로 비용이 줄었는지 확인하기

    그럼 이제 가장 중요한 부분이죠. 이렇게 설정하고 나면 정말 비용 절감이 되는지 어떻게 확인할까요? GitLab은 친절하게도 CI/CD 사용량에 대한 통계를 제공하더라고요. 저는 주로 Settings → CI/CD → Usage Quotas 섹션과 Analytics → CI/CD Analytics를 활용했습니다.

    제 경험으로는, 조건부 린트 잡을 적용하기 전과 후의 Runner minutes(러너 사용 시간) 그래프가 확연히 달라지는 것을 확인할 수 있었습니다. 특히 월말에 청구되는 금액을 비교해보니, 월 300달러 가까이 나가던 CI/CD 비용이 100달러 미만으로 줄어드는 것을 보고 정말 뿌듯했습니다. 🎉 이 정도면 꽤 괜찮은 성과 아닌가요?

    GitLab CI/CD 러너 사용 시간 및 비용 최적화 효과 차트

    GitLab CI/CD Usage Quotas 또는 CI/CD Analytics 대시보드에서 러너 사용 시간(Runner minutes)이 최적화 전후로 극적으로 감소한 것을 보여주는 차트 또는 그래프.

    ✅ 핵심 검증 포인트:

    • Runner minutes 감소: 월별, 주별 러너 사용 시간이 줄어들었는지 확인.
    • 파이프라인 실행 횟수 감소: 불필요한 린트 잡의 실행 횟수가 줄었는지 확인.
    • 청구서 확인: 실제 청구되는 금액이 줄었는지 최종적으로 확인.

    마무리: 작은 변화가 큰 절약을 만듭니다

    오늘은 GitLab CI/CD 비용 최적화, 특히 불필요한 린트 비용을 절감하는 방법에 대해 제 경험을 바탕으로 이야기해 봤습니다. 사실 린트 작업 하나에 월 300달러라는 비용이 나가는 건 좀 과하다 싶었거든요. 하지만 조건부 실행(Conditional Execution)이라는 작은 변화를 통해 예상보다 훨씬 큰 비용 절감 효과를 볼 수 있었습니다.

    이러한 비용 최적화는 린트 작업뿐만 아니라, 빌드(Build), 테스트(Test) 등 다른 CI/CD 잡에도 확장해서 적용할 수 있습니다. 예를 들어, 프론트엔드 코드만 변경되었을 때는 백엔드 테스트를 건너뛰는 식으로요. 항상 “이 잡이 지금 꼭 실행되어야 하는가?”라는 질문을 던져보면 최적화 포인트를 찾기 쉬울 겁니다.

    결국, CI/CD 최적화는 단순히 비용을 줄이는 것을 넘어, 파이프라인의 효율성을 높이고 개발자들이 더 빠르고 정확하게 피드백을 받을 수 있도록 돕는 중요한 과정입니다. 저도 이 과정을 통해 CI/CD에 대한 이해를 한 단계 더 높일 수 있었어요. 여러분도 이 글을 통해 비용 절감과 효율적인 CI/CD 운영에 도움이 되셨기를 바랍니다!

    GitLab CI/CD 비용 절감 전략 요약 인포그래픽

    GitLab CI/CD 비용 절감 전략을 요약하고, 지속적인 최적화의 중요성을 강조하는 인포그래픽 또는 비교표.

    다음 글에서는 GitHub Actions에서도 유사한 비용 최적화 전략을 어떻게 적용할 수 있는지 알아보는 시간을 가져볼게요. 궁금한 점이 있다면 언제든지 댓글로 남겨주세요!

  • [3D Printer] 밤부랩 오픈소스 논란: AGPL 라이선스와 3D 프린팅 커뮤니티

    [3D Printer] 밤부랩 오픈소스 논란: AGPL 라이선스와 3D 프린팅 커뮤니티

    안녕하세요, 13년차 서버실 지킴이입니다. 오늘은 좀 색다른 이야기를 해볼까 해요. 제가 홈랩에서 3D 프린터를 돌리면서 이것저것 만들다 보니, 3D 프린팅 커뮤니티에서 요즘 제일 뜨거운 감자 중 하나인 밤부랩 오픈소스 논란 (Bambu Lab Open-Source Controversy)에 대해 직접 마주하게 되더라고요. 인프라 엔지니어로서 오픈소스 라이선스는 늘 중요한 문제였거든요. 하지만 하드웨어와 소프트웨어가 얽힌 이런 논란은 또 다른 차원의 고민을 안겨주더군요.

    처음엔 ‘3D 프린터 소프트웨어에 무슨 큰일이 있겠어?’ 싶었는데, 내용을 깊이 들여다보니 이게 단순히 기술적인 문제를 넘어선 오픈소스 생태계의 신뢰와 지속 가능성에 대한 이야기더라고요. 저처럼 3D 프린팅에 관심 있는 분들이나, 평소 오픈소스 라이선스에 대해 궁금했던 분들께 제 경험과 분석이 조금이나마 도움이 되었으면 좋겠습니다. 자, 그럼 이 복잡한 논란의 전말과 우리에게 주는 시사점을 함께 파헤쳐 볼까요?

    3D 프린팅, 오픈소스 소프트웨어, 라이선스 문제가 얽힌 개념도

    3D 프린팅, 오픈소스 소프트웨어, 그리고 라이선스 문제가 복잡하게 얽힌 상황을 묘사하는 개념도입니다.

    밤부랩 (Bambu Lab)과 오르카슬라이서 (OrcaSlicer), 그리고 AGPL 라이선스

    이번 논란의 핵심 주체들을 먼저 이해해야 합니다. 제가 처음 밤부랩 X1C를 들여왔을 때, ‘와, 진짜 물건이다!’ 싶었거든요. Bambu Lab (밤부랩)은 최근 몇 년 새 3D 프린팅 시장에 혜성처럼 등장해서 엄청난 속도와 품질로 하이엔드급 성능을 대중화시킨 중국의 3D 프린터 제조사입니다. 특히 P1P, P1S, X1 같은 모델들은 많은 사용자들에게 사랑받고 있죠. 저도 밤부랩 프린터의 빠른 속도와 안정성에 감탄했었고요.

    OrcaSlicer (오르카슬라이서)는 3D 프린팅에서 필수적인 ‘슬라이서’ 소프트웨어 중 하나입니다. 슬라이서는 3D 모델 파일(STL, OBJ 등)을 프린터가 이해할 수 있는 G-code로 변환해주는 역할을 해요. 쉽게 말해, 3D 모델을 얇은 층으로 잘라내어 프린터가 어떤 경로로 움직이며 재료를 쌓을지 지시하는 프로그램이죠. 오르카슬라이서는 원래 PrusaSlicer (프루사슬라이서)라는 또 다른 유명 오픈소스 슬라이서에서 파생된 프로젝트로, 커뮤니티의 기여로 다양한 고급 기능들이 추가되며 인기를 얻었습니다.

    핵심은, 이 오르카슬라이서가 AGPL (GNU Affero General Public License, GNU 아페로 일반 공중 사용 허가서)이라는 오픈소스 라이선스를 따르고 있다는 점이에요. AGPL 라이선스가 뭔지 좀 더 자세히 알아볼까요? GPL(GNU General Public License)은 소프트웨어를 배포할 때 소스코드를 함께 공개해야 한다는 의무를 지웁니다. 그런데 AGPL은 여기서 한 발 더 나아가요. 단순히 소프트웨어를 배포하는 것을 넘어, 네트워크를 통해 소프트웨어를 서비스 형태로 제공하는 경우에도, 사용자가 해당 소프트웨어의 소스코드를 요청하면 공개해야 한다는 강력한 의무를 포함하고 있습니다. 쉽게 말해, 클라우드 서비스처럼 서버에서 돌리는 소프트웨어라도 AGPL 코드를 썼다면 그 소스코드도 공개해야 한다는 거죠. 이게 바로 이번 논란의 불씨가 된 중요한 포인트입니다.

    PrusaSlicer, OrcaSlicer, Bambu Studio 간의 오픈소스 파생 관계 다이어그램

    PrusaSlicer에서 파생된 OrcaSlicer, 그리고 이를 활용한 Bambu Studio의 관계를 보여주는 다이어그램입니다.

    밤부랩 오픈소스 논란의 전말: AGPL 라이선스 준수 문제

    자, 이제 본론입니다. 밤부랩은 자사의 3D 프린터와 함께 사용할 수 있는 Bambu Studio (밤부 스튜디오)라는 자체 슬라이서 소프트웨어를 제공하고 있습니다. 그런데 이 밤부 스튜디오가 초기부터 PrusaSlicer와 OrcaSlicer의 코드를 많이 활용해서 만들어졌다는 건 공공연한 사실이었어요. 오픈소스 커뮤니티에서는 이런 코드 재활용이 흔하고, 라이선스만 잘 지키면 오히려 환영받는 일이죠.

    문제는 밤부랩이 밤부 스튜디오를 개발하면서 AGPL 라이선스 준수에 소홀했다는 의혹이 제기되면서 시작되었습니다. AGPL의 핵심은 ‘네트워크를 통해 서비스를 제공하면 소스코드 공개’인데, 밤부랩의 클라우드 기반 기능들(예: 원격 제어, 파일 업로드 등)이 AGPL로 보호받는 코드와 엮여 있음에도 불구하고, 소스코드 공개가 지연되거나, 라이선스 명시가 불분명했다는 지적이 많았습니다. 특히 OrcaSlicer 개발자들과 커뮤니티는 밤부랩이 자신들의 노력으로 만들어진 코드를 상업적으로 활용하면서 AGPL의 의무를 제대로 이행하지 않는다고 비판했죠.

    제가 처음 이 소식을 접했을 때, ‘아, 또 라이선스 문제구나’ 하는 생각이 들었거든요. 인프라 분야에서도 종종 발생하는 일이라, 솔직히 익숙한 패턴이었습니다. 기업 입장에서는 빠른 제품 출시와 경쟁력 확보가 중요하지만, 오픈소스 라이선스를 무시하거나 소홀히 다루면 결국 이런 논란에 휩싸이게 되죠. 밤부랩은 이에 대해 여러 차례 해명하고 소스코드 공개를 약속했지만, 커뮤니티의 불신은 쉽게 가라앉지 않았습니다. 이미 늦은 대응이거나, 충분치 않다고 받아들여지는 경우가 많았어요.

    ⚠️ 커뮤니티 신뢰와 오픈소스 생태계에 미치는 영향

    이 논란이 단순히 특정 기업과 소프트웨어의 문제를 넘어, 3D 프린팅 오픈소스 커뮤니티와 전체 생태계에 큰 파장을 일으킨다는 점이 중요합니다. 제가 직접 커뮤니티 포럼이나 레딧(Reddit) 같은 곳을 살펴보니, 밤부랩에 대한 실망감이 상당히 컸어요. 많은 개발자와 사용자들은 “우리가 기여해서 만든 코드를 왜 기업이 독점적으로 사용하려 하느냐?”, “오픈소스 정신을 훼손하는 행위다” 같은 격앙된 반응을 보였습니다. 뼈아픈 지적이죠.

    이런 논란은 몇 가지 심각한 문제를 야기할 수 있습니다.

    • 오픈소스 기여 의지 저하: 개발자들이 자신의 노력과 시간을 들여 오픈소스 프로젝트에 기여했는데, 기업이 라이선스 의무를 제대로 지키지 않으면 누가 나서서 기여하려 할까요? “내 노력이 상업적으로 악용될 수도 있다”는 불신이 생기면 오픈소스 생태계 자체가 위축될 수 있습니다.
    • 기업에 대한 신뢰 하락: 밤부랩은 혁신적인 제품으로 많은 팬을 확보했지만, 이번 논란으로 인해 기업 이미지에 큰 타격을 입었습니다. 라이선스 준수는 기업의 윤리적 책임이자 법적 의무인데, 이를 소홀히 하면 소비자의 신뢰를 잃게 되는 거죠.
    • 커뮤니티 분열: 논란은 필연적으로 찬반양론을 만들어내고 커뮤니티를 분열시킵니다. “밤부랩 편을 들면 안 된다”는 분위기가 형성되기도 하고, 반대로 “기업의 입장을 이해해야 한다”는 의견도 나오면서 건전한 토론이 어려워지기도 합니다.

    저도 홈랩에서 다양한 오픈소스 프로젝트를 활용하고 기여도 해봤는데, 이런 식의 논란을 볼 때마다 오픈소스의 본질적인 가치와 상업적 활용 사이의 균형을 맞추는 것이 얼마나 어려운 일인지 다시 한번 느껴지더라고요. 특히 AGPL처럼 강력한 라이선스는 더욱 신중하게 다뤄야 하는 것이 분명합니다.

    기업과 오픈소스 커뮤니티 간의 불신과 분열을 상징하는 이미지

    기업과 오픈소스 커뮤니티 간의 불신과 분열을 상징하는 시각적 은유 이미지입니다.

    ✅ 논란을 통해 배운 점과 앞으로의 방향

    이번 밤부랩 오픈소스 논란은 단순히 3D 프린팅 업계만의 이야기가 아닙니다. 모든 소프트웨어 개발과 서비스 제공에 있어 오픈소스 라이선스에 대한 깊은 이해와 철저한 준수가 얼마나 중요한지 다시 한번 일깨워주는 계기가 되었습니다. 제가 인프라에서 수많은 시스템을 구축하면서도 라이선스 문제는 늘 신경 써야 했던 부분이거든요.

    우리가 이 논란을 통해 얻을 수 있는 교훈은 다음과 같습니다.

    1. 오픈소스 라이선스 교육 및 전문가 활용: 기업은 오픈소스 코드를 활용하기 전에 반드시 해당 라이선스의 내용을 정확히 이해하고, 필요하다면 법률 전문가의 자문을 받아야 합니다. ‘설마 괜찮겠지’ 하는 안일한 태도는 큰 대가를 치르게 된다는 걸 이번 논란이 명확히 보여줍니다.
    2. 투명하고 빠른 소통: 문제가 발생했을 때, 기업은 커뮤니티와 투명하게 소통하고 빠르게 대응해야 합니다. 솔직하게 상황을 인정하고 해결책을 제시하는 것이 신뢰를 회복하는 첫걸음이거든요.
    3. 오픈소스 생태계 존중: 오픈소스는 무료로 사용할 수 있는 코드가 아니라, 수많은 개발자들의 열정과 노력이 담긴 결과물입니다. 이를 상업적으로 활용한다면, 그 노력에 대한 존중과 라이선스 의무 이행은 필수적이에요.

    개인적으로도 이번 논란을 보면서, 제가 홈랩에서 돌리는 다양한 오픈소스 프로젝트들의 라이선스를 다시 한번 꼼꼼히 확인해봐야겠다는 생각을 했습니다. 단순히 작동하는 것 이상으로, 그 기반이 되는 라이선스 규정을 제대로 이해하고 준수하는 것이야말로 진정한 ‘오픈소스 사용자’의 자세가 아닐까 싶어요.

    마무리하며: 상생의 길을 찾아서

    밤부랩 오픈소스 논란은 오픈소스와 상업적 활용의 경계, 그리고 기업의 사회적 책임에 대한 중요한 질문을 던집니다. 3D 프린팅 기술이 점점 더 대중화되고, 많은 기업들이 오픈소스 소프트웨어의 혜택을 받고 있는 이 시점에서, 이 논란은 모두에게 경종을 울리는 사건이라고 생각합니다.

    결국 기업과 오픈소스 커뮤니티는 서로 상생해야 합니다. 기업은 오픈소스의 힘을 빌려 혁신적인 제품을 만들고, 커뮤니티는 기업의 지원과 관심을 통해 더욱 발전할 수 있으니까요. 이를 위해서는 서로에 대한 존중과 약속 이행이 가장 중요하다고 봐요. 밤부랩이 앞으로 어떤 행보를 보일지, 그리고 이 논란이 3D 프린팅 커뮤니티에 어떤 장기적인 영향을 미칠지 계속 지켜봐야 할 것 같습니다. 저도 13년차 엔지니어로서, 이런 기술적, 윤리적 딜레마 속에서 계속 고민하고 배우며 나아가려고 합니다. 다음엔 또 다른 삽질 경험이나 유용한 기술 팁으로 돌아오겠습니다! 🎉

    오픈소스 커뮤니티와 상업 기업 간의 균형 및 라이선스 준수 중요성

    오픈소스 커뮤니티와 상업 기업 간의 균형 잡힌 관계, 그리고 라이선스 준수의 중요성을 상징하는 이미지입니다.

  • [HomeLabs] 홈 어시스턴트와 Matter 연동: 스마트홈 구축 실전 사례와 시행착오

    [HomeLabs] 홈 어시스턴트와 Matter 연동: 스마트홈 구축 실전 사례와 시행착오

    홈 어시스턴트와 Matter 연동: 스마트홈 구축 실전 사례와 시행착오

    안녕하세요, 13년차 서버실 지킴이입니다. 오늘은 스마트홈 구축에 관심 있는 분들이라면 한 번쯤 고민해봤을 주제, 바로 홈 어시스턴트(Home Assistant)와 Matter 연동에 대한 이야기를 풀어볼까 합니다. 제가 홈랩에서 수많은 스마트 기기들을 가지고 씨름하며 얻은 경험과 시행착오를 바탕으로, 어떻게 Matter 기기들을 Home Assistant에 성공적으로 붙일 수 있었는지 실전 사례를 공유해 드릴게요.

    스마트홈, 참 매력적이죠? 저도 처음엔 전등 하나 켜고 끄는 것부터 시작해서 지금은 집안의 거의 모든 것을 자동화하려고 노력하고 있습니다. 그런데 여기서 항상 발목을 잡는 게 있었으니, 바로 파편화(Fragmentation) 문제였습니다. 제조사마다 다른 앱, 다른 프로토콜… 이게 진짜 골치 아프더라고요. 그러다 드디어 Matter라는 새로운 표준이 등장했고, 저처럼 인프라를 좋아하는 사람들에게는 마치 새로운 네트워크 프로토콜을 공부하는 것 같은 설렘을 안겨줬습니다.

    스마트홈 생태계의 복잡성과 Matter 및 Home Assistant 통합 다이어그램

    스마트홈 생태계의 복잡성을 Matter가 어떻게 해결하고 Home Assistant가 이를 통합하는지 보여주는 개념도입니다.

    🤔 스마트홈의 새로운 표준, Matter와 Home Assistant

    본격적인 연동에 앞서, 핵심 개념을 먼저 짚고 넘어가야겠죠? 저도 처음엔 이게 뭔가 싶었는데, 알고 보면 그리 어렵지 않습니다.

    ✔️ 홈 어시스턴트 (Home Assistant, HA)

    홈 어시스턴트(Home Assistant, HA)는 오픈소스 기반의 스마트홈 플랫폼입니다. 쉽게 말해, 온갖 제조사의 스마트 기기들을 한곳에 모아 관리하고 자동화할 수 있게 해주는 나만의 스마트홈 컨트롤 타워라고 보면 됩니다. Raspberry Pi 같은 작은 장치부터 Docker 컨테이너, 가상 머신 등 다양한 환경에 설치할 수 있어서 확장성이 정말 좋더라고요. 저는 Home Assistant OS를 사용하고 있는데, 안정성 면에서 가장 만족스럽더라고요.

    • 로컬 제어(Local Control): 인터넷 연결 없이도 기기 제어가 가능해서 응답 속도가 빠르고 보안에도 유리합니다.
    • 높은 자유도와 커스터마이징(Customization): 수많은 통합(Integrations)과 애드온(Add-ons)을 통해 거의 모든 것을 원하는 대로 설정할 수 있습니다.
    • 강력한 자동화(Automation) 기능: 조건에 따라 다양한 액션을 수행하는 자동화를 만들 수 있습니다.

    ✔️ Matter: 스마트홈의 통합 표준

    Matter는 CSA(Connectivity Standards Alliance)가 개발한 새로운 스마트홈 표준입니다. 기존의 파편화된 스마트홈 시장을 통합하고, 제조사에 상관없이 모든 기기가 서로 통신할 수 있게 하자는 목표를 가지고 있거든요. Wi-Fi, Thread, Ethernet 등 다양한 네트워크 기술 위에서 동작하며, 특히 Thread는 저전력 메시 네트워크를 구성하여 스마트 기기 간의 안정적인 통신을 가능하게 합니다.

    • 상호 운용성(Interoperability): 어떤 제조사의 Matter 기기든 Matter를 지원하는 컨트롤러(예: Home Assistant, Apple HomeKit, Google Home)에 연결할 수 있습니다.
    • 단순한 설정(Simple Setup): QR 코드나 숫자 코드를 이용해 쉽고 빠르게 기기를 추가할 수 있습니다.
    • 로컬 제어(Local Control): Matter 기기 역시 로컬 네트워크 내에서 제어되므로 빠르고 안정적입니다.
    • 보안성(Security): 강력한 암호화와 인증 메커니즘을 통해 보안을 강화했습니다.

    🛠️ 홈 어시스턴트와 Matter 연동, 실전 구현!

    자, 이제 이론은 충분히 익혔으니, 제가 직접 삽질하며 터득한 연동 과정을 단계별로 설명해 드릴게요. “이거 진짜 되네?” 하는 순간을 경험하실 수 있을 겁니다! 🎉

    1. 준비물 확인

    가장 먼저 필요한 준비물들을 확인해야 합니다.

    1. Home Assistant 설치 환경: 저는 Home Assistant OS를 사용하고 있지만, Docker나 가상 머신 환경도 무방합니다. 최신 버전으로 업데이트하는 건 필수더라고요!
    2. Matter 지원 허브 또는 동글: Home Assistant를 Matter 컨트롤러로 사용하려면 Matter over Thread를 위한 Thread Border Router 기능이 필요합니다. Home Assistant SkyConnect 같은 Zigbee/Thread USB 동글이 대표적이죠. 이 동글이 없으면 Matter over Wi-Fi 기기만 연동할 수 있거나, 다른 Thread Border Router (예: Apple HomePod mini, Google Nest Hub)를 활용해야 합니다.
    3. Matter 지원 기기: 테스트를 위해 Matter over Wi-Fi나 Matter over Thread를 지원하는 스마트 플러그나 전구 같은 기기가 필요합니다. Matter를 지원하는 주요 브랜드의 제품들(예: Nanoleaf, Eve, LIFX 등)을 추천합니다.

    2. Home Assistant Matter 애드온 설치 및 설정

    Home Assistant OS 기준으로 설명드릴게요. Configuration -> Add-ons 메뉴로 이동해서 Add-on Store에서 Matter를 검색하고 설치합니다.

    # Home Assistant CLI (SSH 접속 후)
    ha core update
    ha supervisor update
    ha os update
    

    설치 후에는 Matter 애드온을 시작하고, Configuration 탭에서 설정을 확인합니다. 여기서 가장 중요한 건 Thread 네트워크 설정입니다. 만약 SkyConnect 같은 동글을 사용하고 있다면, 이 동글이 Thread Border Router 역할을 할 수 있도록 설정해야 합니다.

    • 새 Thread 네트워크 생성: 집에 Thread 네트워크가 없다면, 여기서 새로운 Thread 네트워크를 생성할 수 있습니다.
    • 기존 Thread 네트워크 참여: 이미 Apple HomePod mini나 Google Nest Hub 같은 Thread Border Router가 있다면, 그 네트워크에 참여하도록 설정할 수 있습니다.

    저는 SkyConnect를 이용해서 새로운 Thread 네트워크를 생성했습니다. 채널 선택은 주변 Wi-Fi와의 간섭을 최소화하도록 잘 고르는 게 중요하더라고요. ⚠️

    Home Assistant Matter 애드온 설정 및 Thread 네트워크 구성 화면

    Home Assistant에서 Matter 애드온을 설정하고 Thread 네트워크를 구성하는 화면입니다.

    3. Matter 기기 페어링

    이제 거의 다 왔습니다! Matter 기기를 Home Assistant에 연동할 차례입니다.

    1. 기기 초기화: Matter 기기를 초기화 상태로 만듭니다. 보통 전원 버튼을 길게 누르거나 여러 번 껐다 켜는 방식입니다. 제조사 설명서를 참고하세요.
    2. Home Assistant에서 기기 추가 시작: Settings -> Devices & Services -> Add Integration으로 이동한 다음, Matter를 검색해서 선택합니다.
    3. QR 코드 또는 숫자 코드 입력: 기기 박스나 설명서에 있는 Matter QR 코드를 스캔하거나, 설정 코드(Setup Code)를 직접 입력합니다.
    4. 페어링 완료: Home Assistant가 기기를 검색하고 연결을 시도합니다. 성공적으로 연결되면 기기가 Home Assistant 대시보드에 나타납니다. 드디어 됐다! 🎉

    ⚠️ 삽질 경험: 흔히 겪는 문제와 해결책

    사실 이 과정이 늘 순탄하지만은 않죠. 제가 겪었던 몇 가지 삽질 경험과 그 해결책을 공유합니다.

    1. Thread 네트워크 불안정 및 채널 간섭

    처음에는 Matter 기기가 자꾸 오프라인으로 떨어지거나 응답이 느리더라고요. 알고 보니 Thread 채널과 주변 Wi-Fi 채널이 간섭을 일으키고 있었던 겁니다. Thread와 Wi-Fi는 모두 2.4GHz 대역을 사용하기 때문에, 채널 선택이 정말 중요합니다.

    • 해결책: 💡 Thread Border Router (예: SkyConnect)의 Thread 채널을 Wi-Fi와 겹치지 않게 변경했습니다. Wi-Fi에서 주로 사용되는 채널(1, 6, 11번)을 피하고, Thread는 이들과 거리가 먼 채널(예: 25번 근처)을 선택하는 것이 효과적이더라고요.
    • 팁: Home Assistant의 Developer Tools -> States에서 thread 관련 엔티티의 정보를 확인해보면 현재 채널과 신호 강도를 파악할 수 있습니다.

    2. 페어링 실패 및 타임아웃

    QR 코드를 스캔했는데도 “기기를 찾을 수 없습니다”라고 뜨거나, 페어링 과정에서 타임아웃이 나는 경우가 있었습니다.

    • 해결책:
      1. 기기 초기화 재확인: 기기가 제대로 초기화 상태에 있는지 다시 확인했습니다.
      2. 거리 문제: 처음 페어링할 때는 Matter 컨트롤러(Home Assistant)와 기기 간의 거리를 가깝게 유지하는 게 좋더라고요.
      3. Home Assistant 재시작: 가끔은 Home Assistant Core를 재시작하는 것만으로도 문제가 해결되기도 합니다.
      4. 네트워크 분리: Wi-Fi 기반과 Thread 기반 Matter 기기를 동시에 연동할 때 네트워크 설정이 꼬이는 경우도 있습니다. 가능하면 초반에는 한 종류의 네트워크 기반 기기부터 연동해보는 걸 추천합니다.

    3. Matter 기기의 제한적인 기능

    어떤 Matter 기기는 연동은 되는데, 모든 기능(예: 특정 센서 데이터, 고급 조명 효과)이 Home Assistant에 완벽하게 노출되지 않는 경우도 있었습니다.

    • 해결책: Matter 표준 자체가 아직 진화 과정에 있어서 모든 기기의 모든 기능을 100% 지원하지 못할 수도 있습니다. Home Assistant 커뮤니티나 제조사 포럼에서 해당 기기의 Matter 지원 범위에 대한 정보를 찾아보는 게 도움이 됩니다. 간혹 펌웨어 업데이트로 해결되는 경우도 있거든요.

    ✅ 연동 결과 및 스마트홈 자동화 활용

    몇 번의 삽질 끝에 드디어 모든 기기가 Home Assistant에 성공적으로 연동되었습니다! 🥳

    대시보드에서 연동된 Matter 기기들을 한눈에 확인할 수 있었고, 전구의 밝기를 조절하거나 스마트 플러그를 켜고 끄는 등 기본적인 제어가 모두 가능했습니다.

    Home Assistant 대시보드에 연동된 Matter 기기 목록

    Home Assistant 대시보드에서 Matter 기기들이 성공적으로 연동되어 제어 가능한 모습을 보여줍니다.

    자동화 예시: “굿모닝” 루틴

    Home Assistant의 진가는 역시 자동화죠. 연동된 Matter 기기들을 활용해 간단한 자동화를 만들어봤습니다.

    automation:
      - alias: 'Good Morning Routine with Matter Lights'
        trigger:
          - platform: time
            at: '07:00:00'
        condition:
          - condition: state
            entity_id: 'binary_sensor.bedroom_motion_sensor' # Matter 센서가 있다면
            state: 'off' # 움직임이 없으면
        action:
          - service: light.turn_on
            target:
              entity_id: 'light.bedroom_ceiling_light' # Matter 전등
            data:
              brightness_pct: 50
              color_temp: 4000
          - service: switch.turn_on
            target:
              entity_id: 'switch.coffee_maker_plug' # Matter 스마트 플러그
    

    매일 아침 7시, 침실에 움직임이 없으면 (아직 잠들어 있다면) 침실 전등이 50% 밝기로 서서히 켜지고, 커피 메이커 플러그가 자동으로 켜지는 자동화입니다. 별거 아닌 것 같아도 아침이 훨씬 부드러워지더라고요. 이거 진짜 편하더라고요!

    마무리하며: Matter, 스마트홈의 미래를 열다

    오늘은 제가 Home Assistant와 Matter 기기를 연동하면서 겪었던 실전 경험과 삽질 과정을 솔직하게 공유해 드렸습니다. Matter는 아직 초기 단계이고, 모든 기기가 완벽하게 연동되는 것은 아니지만, 스마트홈 시장의 파편화를 해결하고 진정한 상호 운용성을 제공하려는 시도 자체만으로도 충분히 가치 있다고 생각합니다.

    물론 Matter 연동 과정이 항상 쉽지만은 않았습니다. 저도 처음엔 “왜 안 되지?” 하며 밤늦게까지 헤매기도 했었죠. 하지만 하나하나 해결해나가면서 얻는 지식과 성취감은 인프라 엔지니어로서의 저에게 큰 즐거움이었습니다. 혹시 이런 경험 있으신가요? 😃

    Matter와 Home Assistant 로고를 통한 스마트홈 통합 미래 인포그래픽

    Matter와 Home Assistant가 함께 스마트홈의 미래를 열어가는 모습을 시각적으로 표현한 인포그래픽입니다.

    스마트홈 구축은 단순히 기기를 설치하는 것을 넘어, 나만의 공간을 더 편리하고 효율적으로 만드는 여정이라고 생각합니다. Home Assistant와 Matter는 이 여정을 더욱 풍요롭게 만들어 줄 강력한 도구가 될 것입니다. 다음 글에서는 Matter 기기를 활용한 좀 더 복잡한 자동화 시나리오나, Zigbee, Z-Wave 같은 다른 프로토콜과의 연동 경험에 대해서도 다뤄볼 예정입니다. 그때까지 즐거운 홈랩 생활 이어가시길 바랍니다!

  • [Nas] Cloudflare Tunnel vs. VPN: 홈서버 원격 접속 비용 효율성 비교 2026년 9월 업데이트

    [Nas] Cloudflare Tunnel vs. VPN: 홈서버 원격 접속 비용 효율성 비교 2026년 9월 업데이트

    💡 도입: 홈서버 원격 접속, 이젠 선택이 아닌 필수!

    안녕하세요, 13년차의 서버실 주인장입니다. 홈랩을 운영하는 인프라 엔지니어라면 누구나 한 번쯤은 이런 고민을 해봤을 거예요. “집에 있는 내 소중한 서버에 외부에서 안전하게 접속하고 싶다!” 저도 처음엔 공유기 포트 포워딩(Port Forwarding)으로 시작했었죠. 특정 포트를 열어두고 DDNS(Dynamic DNS)를 걸어서 접속했었는데, 이게 보안적으로 너무 취약하더라고요.

    그러다 보니 자연스럽게 VPN(Virtual Private Network), WireGuard, OpenVPN 같은 기술을 살펴보게 됐어요. 그런데 VPN도 서버를 직접 구축하고 관리하는 게 생각보다 손이 많이 가거든요. 그러다 Cloudflare Tunnel이라는 녀석을 알게 됐는데, 이거 진짜 물건이더라고요. 포트 포워딩 없이, 심지어 개인 홈랩 기준으로는 무료 플랜만으로도 꽤 강력한 보안 구성을 만들 수 있으니까요.

    그래서 오늘은 Cloudflare Tunnel과 VPN, 이 두 가지 홈서버 원격 접속 방법을 2026년 9월 기준으로 다시 비교해보려고 합니다. 특히 Cloudflare Zero Trust, WARP, private network routing, NAS 원격 접속, 홈랩 보안 같은 키워드가 중요해진 만큼 예전 글에서 살짝 오래된 부분도 같이 손봤습니다.

    홈서버 원격 접속을 위한 Cloudflare Tunnel과 VPN의 개념도를 나타낸 그림입니다. 외부에서 안전하게 홈서버에 접근하는 방식을 한눈에 볼 수 있습니다.

    🤔 Cloudflare Tunnel, VPN: 개념부터 잡아봅시다!

    본격적인 비교에 앞서, 두 기술이 정확히 어떤 것인지 개념부터 확실하게 짚고 넘어가는 게 좋겠죠? 쉽게 말해드릴게요.

    Cloudflare Tunnel (클라우드플레어 터널)

    Cloudflare Tunnel은 제로 트러스트(Zero Trust) 보안 모델을 기반으로 하는 서비스예요. 내부 네트워크의 포트를 외부로 직접 열지 않고, 홈서버에 설치한 cloudflared가 Cloudflare 네트워크로 아웃바운드 터널을 만드는 방식입니다.

    • 작동 방식: 홈서버의 cloudflared가 Cloudflare 에지 네트워크로 먼저 연결합니다. 외부 사용자가 your-service.example.com 같은 도메인으로 접속하면 Cloudflare가 해당 요청을 터널을 통해 홈서버 내부 서비스로 전달해요.
    • 주요 장점: 포트 포워딩이 필요 없고, 실제 공인 IP가 노출되지 않으며, SSL/TLS와 DDoS 보호를 Cloudflare 앞단에서 활용할 수 있습니다.
    • 2026년 기준 보완점: 예전에는 “특정 웹 서비스 공개” 느낌이 강했지만, 지금은 Cloudflare One Client(WARP)와 Tunnel CIDR 라우팅을 조합해 사설 IP 대역까지 연결하는 구성이 더 자연스러워졌습니다. 다만 이 경우에는 클라이언트 등록, Split Tunnel, Gateway 정책까지 같이 설계해야 합니다.

    VPN (Virtual Private Network, 가상 사설망)

    VPN은 이름 그대로 가상 사설망을 구축해서 외부 네트워크에서도 마치 집 안 네트워크에 있는 것처럼 접속하는 기술이에요. 홈랩에서는 여전히 WireGuard가 가장 가볍고 빠른 선택지로 많이 쓰이고, OpenVPN은 호환성이 좋은 편입니다.

    • 작동 방식: VPN 클라이언트가 VPN 서버로 암호화된 터널을 만들고, 클라이언트는 할당받은 내부 IP를 통해 NAS, Proxmox, Docker 서비스, 관리 페이지 등에 접근합니다.
    • 주요 장점: 네트워크 전체 접근이 쉽습니다. 특정 웹 서비스뿐 아니라 SSH, SMB, RDP, 내부 DNS 등 홈 네트워크 전체를 다뤄야 한다면 여전히 VPN이 편해요.
    • 주의할 점: VPN 서버 포트를 외부에 열어야 하는 경우가 많고, 인증키 관리, 방화벽, 라우팅, 업데이트를 꾸준히 챙겨야 합니다.

    ⚔️ Cloudflare Tunnel vs. VPN: 비용 효율성 및 주요 차이점 비교

    이제 두 기술의 가장 중요한 차이점, 그리고 홈랩 운영자의 입장에서 어떤 방식이 더 비용 효율적인지 비교해볼까요?

    기준 Cloudflare Tunnel VPN
    비용
    • 무료 플랜: 개인 홈서버, NAS 원격 접속, 소규모 홈랩에는 여전히 충분한 편입니다.
    • 팀 단위 Access, Gateway, 로그 보관, 고급 보안 정책이 필요하면 유료 플랜을 검토해야 합니다.
    • 홈서버에서 직접 운영하면 추가 서버 비용은 거의 없지만, 전기료와 유지보수 비용은 발생합니다.
    • 클라우드 VPS에 VPN을 두면 월별 요금이 붙습니다.
    설정 난이도
    • 웹 서비스 공개만 한다면 비교적 간단합니다.
    • 2026년 기준으로는 Cloudflare Zero Trust 대시보드에서 터널과 퍼블릭 호스트네임을 만드는 방식이 가장 편합니다.
    • WireGuard는 예전보다 쉬워졌지만, 라우팅과 방화벽을 이해해야 삽질이 줄어듭니다.
    • 공유기, DDNS, 포트 포워딩, 키 관리가 필요할 수 있습니다.
    보안 모델
    • 제로 트러스트: 서비스별 접근 정책, 이메일 OTP, MFA, IdP 연동을 붙이기 좋습니다.
    • 내부 포트를 직접 열지 않는 구조라 공격 표면을 줄이기 좋습니다.
    • 경계 기반 보안: VPN에 들어오면 내부망에 들어온 것과 비슷한 권한을 갖기 쉽습니다.
    • 키 유출, 취약한 VPN 서버, 과도한 내부 접근 권한을 조심해야 합니다.
    접속 범위
    • 웹 앱, SSH, RDP 같은 서비스 단위 공개에 강합니다.
    • WARP와 Tunnel CIDR 라우팅을 쓰면 사설 IP 대역 접근도 가능하지만, 설정은 단순 웹 공개보다 복잡합니다.
    • 네트워크 전체 접근이 가장 자연스럽습니다.
    • NAS 파일 공유, 내부 DNS, 여러 장비 관리에는 여전히 강합니다.
    성능
    • Cloudflare 에지 네트워크를 거치므로 웹 서비스에는 체감이 좋은 경우가 많습니다.
    • 대용량 파일 전송이나 실시간 내부망 작업은 구성에 따라 VPN이 더 단순하고 빠를 수 있습니다.
    • 성능은 집 인터넷 업로드 속도, VPN 서버 성능, 암호화 오버헤드에 좌우됩니다.
    • WireGuard는 대체로 가볍고 빠른 편입니다.
    추가 기능
    • Cloudflare Access, Gateway 정책, WAF, Turnstile, 로그, IdP 연동과 결합하기 좋습니다.
    • 원격 접속 자체에 집중합니다. 세밀한 사용자별 웹 접근 제어는 별도 솔루션이 필요할 수 있습니다.
    Cloudflare Tunnel과 VPN 기능 및 비용 효율성 비교 인포그래픽

    정리하자면, Cloudflare Tunnel은 웹 기반 홈서버 서비스, NAS 관리 페이지, 개인 대시보드, SSH 접속을 안전하게 노출하고 싶을 때 비용 효율이 좋습니다. 반면 VPN은 홈 네트워크 전체 접근, SMB 파일 공유, 내부 장비 관리, 모든 트래픽 암호화가 필요할 때 여전히 강력합니다.

    🛠️ Cloudflare Tunnel 실전 구축: 홈서버 원격 접속!

    이제 이론은 충분히 봤으니, 홈랩에 Cloudflare Tunnel을 구축하는 과정을 2026년 기준으로 정리해볼게요. 예전처럼 CLI만으로 만들 수도 있지만, 지금은 Cloudflare Zero Trust 대시보드에서 터널을 만들고 Connector 토큰으로 서버를 등록하는 방식이 가장 직관적입니다.

    1단계: Cloudflare 계정, 도메인, Zero Trust 조직 준비

    먼저 Cloudflare 계정을 만들고, 사용할 도메인을 Cloudflare DNS에 등록합니다. 그다음 Cloudflare 대시보드에서 Zero Trust 조직을 생성해야 해요. Free 플랜을 선택해도 결제 정보 입력 단계가 나올 수 있지만, 무료 플랜 자체는 개인 홈랩 테스트에 충분합니다.

    도메인은 꼭 비싼 걸 살 필요는 없고, NAS 원격 접속용으로 nas.example.com, home.example.com, ssh.example.com처럼 서브도메인을 나눠 쓰면 관리가 편합니다.

    2단계: cloudflared 설치 및 최신 버전 확인

    2026년 9월 기준 최신 cloudflared 릴리스는 2026.9.1입니다. 2026.8.0 계열에는 일부 HTTP origin 요청에서 trailing slash 처리 문제가 보고됐기 때문에, 가능하면 2026.8.2 이상 또는 최신 버전으로 올리는 걸 추천합니다.

    # 리눅스 AMD64 기준 cloudflared 설치 예시
    curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared
    chmod +x /usr/local/bin/cloudflared
    
    # 설치 확인
    cloudflared --version

    라즈베리 파이나 ARM 서버를 쓴다면 cloudflared-linux-arm64 또는 패키지 저장소 방식을 쓰는 게 좋습니다. 그리고 2027년부터는 32비트 Windows와 Intel 기반 macOS용 cloudflared 신규 빌드가 중단될 예정이라, 오래된 장비에 설치해둔 분들은 미리 ARM64, x86_64 Linux, Apple Silicon macOS 환경으로 옮길 계획을 세워두는 게 좋아요.

    3단계: 터널 생성 및 설정

    CLI로 직접 만드는 방식은 여전히 사용할 수 있습니다.

    # Cloudflare 계정 로그인
    cloudflared tunnel login
    
    # 터널 생성
    cloudflared tunnel create my-homelab-tunnel

    설정 파일은 보통 /etc/cloudflared/config.yaml에 둡니다.

    tunnel: [YOUR_TUNNEL_UUID]
    credentials-file: /root/.cloudflared/[YOUR_TUNNEL_UUID].json
    
    ingress:
      - hostname: your-service.your-domain.com
        service: http://localhost:8080
      - service: http_status:404

    요즘 제가 더 추천하는 방식은 Zero Trust 대시보드에서 Networks > Tunnels로 들어가 터널을 만들고, 안내되는 Connector 설치 명령을 서버에 붙여 넣는 방법입니다. 이 방식은 자격 증명 파일과 서비스 등록 과정이 덜 헷갈려요.

    4단계: DNS 레코드 설정

    CLI 방식이라면 다음 명령으로 CNAME 레코드를 만들 수 있습니다.

    cloudflared tunnel route dns my-homelab-tunnel your-service.your-domain.com

    대시보드 방식이라면 터널 설정의 Public Hostname에서 your-service.your-domain.com을 추가하고, 내부 서비스 주소를 http://localhost:8080처럼 입력하면 됩니다. 생성된 CNAME은 [YOUR_TUNNEL_UUID].cfargotunnel.com 형태이며, Cloudflare 프록시가 켜져 있어야 보안과 성능 이점을 제대로 활용할 수 있습니다.

    5단계: 터널 실행 및 서비스 등록

    CLI 방식에서는 다음처럼 systemd 서비스로 등록할 수 있습니다.

    sudo cloudflared tunnel service install
    sudo systemctl enable --now cloudflared
    sudo systemctl status cloudflared

    대시보드에서 만든 터널은 보통 아래처럼 토큰이 포함된 설치 명령을 제공합니다.

    sudo cloudflared service install [TOKEN]
    sudo systemctl status cloudflared

    systemctl status cloudflared에서 active (running) 상태가 보이면 1차 성공입니다. 이후 Cloudflare Zero Trust 대시보드에서도 터널 상태가 Healthy로 표시되는지 확인해보세요.

    Cloudflare Zero Trust 대시보드 터널 연결 성공 스크린샷

    ⚠️ 삽질 경험: Service Tunnel Error 해결하기

    제가 처음 Cloudflare Tunnel을 설정할 때 가장 많이 겪었던 오류 중 하나가 바로 Service Tunnel Error였어요. 터널은 생성됐는데, 실제 서비스가 안 열리는 답답한 상황이죠.

    1. config.yaml 파일 오류: YAML은 들여쓰기에 민감합니다. 탭 대신 스페이스를 쓰고, ingress 마지막에는 http_status:404 같은 기본 규칙을 넣어주세요.
    2. 잘못된 service 주소: http://localhost:8080으로 적었는데 실제 컨테이너가 다른 포트에서 떠 있거나, Docker 네트워크 때문에 localhost가 맞지 않는 경우가 많습니다.
    3. 내부 서비스 미실행: docker ps, systemctl status, ss -tulnp로 실제 서비스가 리스닝 중인지 확인하세요.
    4. 방화벽 문제: ufw, firewalld, NAS 자체 방화벽이 cloudflared의 내부 접근을 막을 수 있습니다.
    5. cloudflared 버전 문제: 특정 릴리스에서 회귀 버그가 생길 수 있으니, 이상 증상이 있으면 최신 안정 버전으로 올려보세요.
    6. 로그 확인: journalctl -u cloudflared --since '10 minutes ago' 또는 대시보드 Connector 로그를 보면 원인이 훨씬 빨리 보입니다.

    저도 “아, 이거 왜 안 되지?” 하면서 한참을 붙잡고 있다가 로그를 보니 내부 서비스 포트가 틀렸던 적이 있습니다. 결국 터널 문제처럼 보여도 절반은 origin 서비스 주소 문제더라고요.

    ✅ 검증 및 결과: 제로 트러스트 원격 접속의 편리함

    모든 설정을 마쳤다면 브라우저에서 your-service.your-domain.com으로 접속해보세요. 정상적으로 홈서버 서비스 화면이 뜨면 성공입니다.

    • 안전한 접속: 포트 포워딩 없이 실제 IP를 숨긴 채 홈서버에 접속할 수 있습니다.
    • Cloudflare 보호: HTTPS, DDoS 방어, 프록시 기반 보호를 쉽게 붙일 수 있습니다.
    • Zero Trust Access 연동: 이메일 OTP, MFA, Google Workspace, GitHub 같은 IdP 연동으로 사용자 인증을 추가할 수 있습니다.
    • NAS 원격 접속 최적화: Synology, TrueNAS, Unraid, Proxmox 대시보드처럼 웹 기반 관리 화면을 공개할 때 특히 편합니다.
    Cloudflare Tunnel을 통한 홈서버 웹 서비스 접속 화면

    🆕 2026년 9월 기준 새로 챙겨볼 변화

    원문 작성 이후 홈서버 원격 접속 쪽에서 체크할 만한 변화가 몇 가지 있었습니다.

    • cloudflared 최신 버전: 2026년 9월 기준 최신 릴리스는 2026.9.1입니다. 자동 업데이트나 정기 업데이트 루틴을 잡아두는 걸 추천합니다.
    • 오래된 클라이언트 지원 축소: 2027년부터 32비트 Windows와 Intel 기반 macOS용 신규 cloudflared 빌드가 중단될 예정입니다. 오래된 맥 미니나 구형 Windows 장비를 터널 서버로 쓰고 있다면 이전 계획이 필요합니다.
    • Private Network Routing 강화: Cloudflare Tunnel은 이제 단순 웹 앱 공개뿐 아니라 WARP 클라이언트와 Tunnel CIDR 라우팅을 통해 사설망 접근 시나리오에도 자주 쓰입니다. 전통적인 VPN 대체 구성이 더 현실적이 됐어요.
    • Access for Infrastructure: SSH 같은 인프라 접근을 사용자, 포트, 프로토콜 단위로 더 세밀하게 제어하는 기능도 계속 강화되고 있습니다. 홈랩에서도 SSH를 그냥 인터넷에 열어두는 방식은 이제 굳이 선택할 이유가 줄었습니다.
    • 보안 키워드 변화: 단순 “원격 접속”보다 Zero Trust NAS, Cloudflare WARP, 홈랩 보안, 포트포워딩 대체, self-hosted secure access 같은 관점으로 설계하는 흐름이 강해졌습니다.

    💡 마무리: 어떤 방식이 나에게 맞을까?

    결론은 꽤 명확합니다. 웹 기반 서비스 몇 개를 안전하게 공개하고 싶다면 Cloudflare Tunnel이 비용 효율과 관리 편의성 면에서 아주 좋습니다. NAS 관리 페이지, 개인 위키, 홈 대시보드, 개발용 웹앱, SSH 접근 정도라면 포트 포워딩 없이 깔끔하게 운영할 수 있어요.

    반대로 내부망 전체를 내 노트북으로 끌고 와야 한다면 VPN이 아직도 편합니다. SMB 파일 공유, 내부 DNS, 여러 장비의 관리 포트, 대용량 파일 작업이 많다면 WireGuard 기반 VPN이 더 단순할 수 있어요.

    개인적으로는 두 가지를 같이 씁니다. 평소 자주 쓰는 웹 서비스는 Cloudflare Tunnel로 열고, 내부망 전체 접근이 필요할 때만 WireGuard VPN을 켜는 식이죠. 홈서버 원격 접속은 하나만 고집하기보다, 서비스 성격에 맞게 나눠 쓰는 게 제일 편하더라고요.

    🔄 마지막 업데이트: 2026년 09월

  • [k8s] 쿠버네티스 Secret 관리 베스트 프랙티스: 민감 데이터 보안 강화 전략

    [k8s] 쿠버네티스 Secret 관리 베스트 프랙티스: 민감 데이터 보안 강화 전략

    도입부: 민감 데이터, 이렇게 방치해도 될까요?

    안녕하세요, 13년차 서버실 지킴이입니다. 쿠버네티스(Kubernetes)를 운영하다 보면 정말 많은 난관에 부딪히게 되죠. 그중에서도 민감 데이터(Sensitive Data) 관리는 늘 머리 아픈 숙제였어요. 저도 처음엔 별생각 없이 Secret 리소스를 사용했었는데, 시간이 지날수록 ‘이대로 괜찮을까?’ 하는 불안감이 커지더라고요. 개발자들이 접속 정보, API 키 같은 걸 그냥 Secret에 넣고 쓰는 모습을 보면서 ‘언젠가 터지겠구나’ 싶었거든요.

    실제로 쿠버네티스 환경에서 Secret 관리가 제대로 되지 않아 보안 사고로 이어진 사례도 심심치 않게 들려옵니다. 외부 공격은 물론이고, 내부에서도 불필요한 접근 권한 때문에 문제가 생기기도 하고요. 그래서 오늘은 제가 13년간 인프라 엔지니어로 일하며 겪었던 경험과 홈랩에서 직접 실험해본 것들을 바탕으로, 쿠버네티스 Secret 관리 베스트 프랙티스 체크리스트를 공유해드리려고 합니다. 민감 데이터를 안전하게 보호하기 위한 전략들을 함께 알아볼까요?

    쿠버네티스 클러스터 내 Secret 관리의 중요성을 보여주는 개요 다이어그램

    쿠버네티스 클러스터 내 Secret 관리의 중요성을 보여주는 개요 다이어그램입니다.

    쿠버네티스 Secret, 넌 누구니? (개념 설명)

    먼저, 쿠버네티스 Secret이 정확히 무엇인지부터 짚고 넘어갈게요. 쿠버네티스 Secret(시크릿)은 말 그대로 민감한 정보(Sensitive Information)를 저장하기 위한 오브젝트입니다. 데이터베이스 암호, OAuth 토큰, SSH 키 등을 여기에 저장하고 파드(Pod)에 주입해서 사용하죠. 흔히 환경 변수나 파일 형태로 파드에 마운트(Mount)해서 애플리케이션이 접근하도록 합니다.

    쉽게 말해, 컨테이너 이미지에 직접 민감 정보를 하드코딩(Hard-coding)하거나 YAML 매니페스트에 평문(Plaintext)으로 노출하는 대신, 쿠버네티스 자체적으로 제공하는 저장소를 이용하는 방식이라고 보시면 됩니다. 그런데 여기서 중요한 포인트! 쿠버네티스 Secret은 기본적으로 Base64(베이스64) 인코딩만 되어 있을 뿐, 암호화(Encryption)되어 있지 않습니다. 이 말은 인코딩된 문자열을 누구나 쉽게 디코딩해서 원본 값을 볼 수 있다는 뜻이에요. 이걸 모르고 Secret이 완전히 안전하다고 생각했다간 큰코다칠 수 있습니다.

    Secret 관리, 어떤 점이 문제일까요? (삽질 경험 공유)

    저도 처음엔 ‘그래도 쿠버네티스에서 제공하는 거니까 안전하겠지!’ 하고 막연하게 생각했었어요. 그래서 개발팀에서 요청하는 대로 DB 접속 정보나 외부 API 키를 kubectl create secret generic 명령어로 뚝딱 만들어서 배포했었죠. 그러다가 문득 kubectl get secret <secret-name> -o yaml 명령어를 쳐봤는데, 인코딩된 값들이 너무 쉽게 디코딩되는 걸 보고 깜짝 놀랐습니다. ‘아, 이건 아니구나’ 싶더라고요. 사실 Secret의 가장 큰 문제점은 다음과 같습니다.

    • Base64 인코딩은 암호화가 아니다: 위에서 설명했듯이, 누구나 쉽게 원본 값을 볼 수 있다는 점이 가장 치명적입니다.
    • etcd(엣시디)에 평문 저장 가능성: 쿠버네티스의 모든 오브젝트는 etcd라는 분산 키-값 저장소에 저장됩니다. etcd 자체가 암호화되어 있지 않다면, Secret 내용이 그대로 노출될 수 있습니다.
    • 접근 제어의 복잡성: Secret에 대한 접근 권한을 세밀하게 제어하지 않으면, 불필요한 사용자나 파드가 민감 정보에 접근할 수 있게 됩니다. RBAC(Role-Based Access Control) 설정을 잘못하면 문제가 생기죠.
    • GitOps(깃옵스) 환경과의 충돌: Secret을 Git 리포지토리에 저장하고 싶은데, 평문으로 올릴 수는 없잖아요? 그렇다고 인코딩된 값을 올리는 것도 보안상 좋지 않습니다. 버전 관리와 보안 사이에서 딜레마에 빠지게 됩니다.

    이런 문제점들 때문에 제가 밤늦게까지 홈랩에서 씨름하며 여러 솔루션을 찾아보고 적용해봤었죠. 삽질 좀 했습니다 ㅎㅎ

    민감 데이터 보안 강화 전략 체크리스트 (베스트 프랙티스)

    이제 본격적으로 쿠버네티스 Secret 관리 베스트 프랙티스 체크리스트를 공유해드릴게요. 이 전략들을 하나씩 적용해나가시면 훨씬 안전한 쿠버네티스 환경을 만들 수 있을 겁니다.

    1. etcd 암호화 (Encryption at Rest)

    가장 기본 중의 기본입니다. 쿠버네티스 클러스터의 핵심 데이터 저장소인 etcd에 저장되는 모든 데이터를 암호화해야 합니다. 특히 Secret 오브젝트는 반드시 암호화해야 합니다. 이를 Encryption at Rest(저장 데이터 암호화)라고 부르는데요, kube-apiserver(쿠브-API서버) 설정을 통해 Secret 리소스만 선택적으로 암호화할 수 있습니다.

    2. RBAC(Role-Based Access Control)으로 Secret 접근 제어

    누가 어떤 Secret에 접근할 수 있는지 RBAC를 통해 세밀하게 제어해야 합니다. 최소 권한 원칙(Principle of Least Privilege)을 적용하여, 꼭 필요한 사용자나 파드에게만 필요한 Secret에 대한 읽기 권한을 부여해야 합니다. 예를 들어, 특정 네임스페이스(Namespace)의 파드만 해당 네임스페이스의 Secret을 사용할 수 있도록 제한하는 것이죠.

    3. 외부 Secret 관리 솔루션 활용

    쿠버네티스 기본 Secret의 한계를 보완하기 위해 외부 Secret 관리 솔루션을 적극적으로 고려해보세요. 제가 홈랩에서도 여러 솔루션을 테스트해봤는데, 정말 편하더라고요.

    • HashiCorp Vault(하시코프 볼트): 중앙 집중식 Secret 관리 솔루션의 대명사입니다. 동적 Secret 생성, Secret 리스(Lease), 감사 로그(Audit Log) 등 강력한 기능을 제공합니다. 쿠버네티스와의 연동도 잘 되어 있어서 많은 기업에서 사용하고 있습니다.
    • Sealed Secrets(실드 시크릿): Bitnami에서 개발한 솔루션으로, Secret을 암호화하여 Git 리포지토리에 안전하게 저장할 수 있게 해줍니다. 클러스터 내의 컨트롤러(Controller)가 암호화된 SealedSecret을 복호화하여 일반 Secret으로 만들어줍니다. GitOps 환경에서 특히 유용하죠.
    • 클라우드 제공 Secret Manager: AWS Secrets Manager, Google Secret Manager, Azure Key Vault 등 클라우드 서비스에서 제공하는 Secret 관리 솔루션을 활용하는 것도 좋은 방법입니다.
    쿠버네티스와 외부 Secret 관리 솔루션(Vault, Sealed Secrets) 연동 아키텍처 예시입니다.

    쿠버네티스와 외부 Secret 관리 솔루션(Vault, Sealed Secrets) 연동 아키텍처 예시입니다.

    4. Kubelet Secret 볼륨 암호화 (KMS Provider)

    파드에 마운트(Mount)되는 Secret 볼륨은 tmpfs(임시 파일 시스템)에 저장되지만, 만약 Kubelet(쿠블릿) 노드가 탈취당했을 경우 메모리 덤프 등을 통해 Secret에 접근할 위험이 있습니다. 클라우드 환경에서는 KMS(Key Management Service) Provider를 활용하여 Secret 볼륨을 암호화할 수 있습니다. 예를 들어 AWS EKS나 GCP GKE에서는 KMS를 etcd 암호화뿐만 아니라 Secret 볼륨 암호화에도 활용할 수 있습니다.

    5. Secret 변경 시 애플리케이션 재시작/재배포

    쿠버네티스 Secret은 파드에 환경 변수나 볼륨으로 주입되는데, Secret의 내용이 변경되어도 파드는 자동으로 업데이트된 Secret을 로드하지 않습니다. 즉, 변경 사항을 적용하려면 해당 파드를 재시작(Restart)하거나 재배포(Redeploy)해야 합니다. 이 점을 잊고 ‘왜 Secret 바꿨는데 적용이 안 되지?’ 하고 저처럼 삽질하는 일이 없으시길 바랍니다. Deployment(디플로이먼트)의 Hash(해시) 기반 롤링 업데이트(Rolling Update)를 활용하거나, Reloader 같은 툴을 사용하면 좀 더 자동화할 수 있습니다.

    6. Secret Rotation (정기적 교체)

    아무리 강력하게 암호화하고 접근 제어를 해도, Secret이 영원히 안전하다고 보장할 수는 없습니다. 따라서 Secret을 정기적으로 교체(Rotation)하는 정책을 수립하고 자동화하는 것이 중요합니다. 예를 들어 데이터베이스 암호는 3개월마다, API 키는 6개월마다 교체하는 식이죠. 외부 Secret 관리 솔루션들은 이러한 Secret Rotation 기능을 자체적으로 제공하기도 합니다.

    실전 적용 가이드: etcd 암호화와 Sealed Secrets 예시

    이론만으로는 부족하죠! 제가 직접 적용해봤던 etcd 암호화와 Sealed Secrets의 간단한 예시를 보여드릴게요.

    etcd 암호화 설정

    kube-apiserver 설정을 수정하여 etcd에 저장되는 Secret을 암호화할 수 있습니다. EncryptionConfiguration API를 사용하는데, AES-CBC(고급 암호화 표준-Cipher Block Chaining) 방식이 널리 사용됩니다.

    apiVersion: apiserver.config.k8s.io/v1
    kind: EncryptionConfiguration
    resources:
      - resources:
          - secrets
        providers:
          - aescbc:
              keys:
                - secretbox:
                    secret: <YOUR_AES_KEY_BASE64> # Base64 인코딩된 32바이트 AES 키
          - identity: {}
          - secretbox: {}
    

    여기서 <YOUR_AES_KEY_BASE64>는 직접 생성한 AES 키를 Base64 인코딩한 값입니다. 이 키는 안전하게 보관해야 합니다. 이 설정 파일을 kube-apiserver에 적용하면, 이후 생성되는 Secret들은 모두 etcd에 암호화된 상태로 저장됩니다. 기존 Secret들도 재작성(rewrite)해야 암호화가 적용됩니다.

    Sealed Secrets 도입

    Sealed Secrets는 GitOps 환경에서 Secret을 안전하게 관리하기 위한 좋은 방법입니다. 먼저 클러스터에 Sealed Secrets 컨트롤러를 설치합니다.

    # 컨트롤러 설치 (helm 사용 예시)
    helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
    helm repo update
    helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system
    
    # public key 추출
    kubeseal --fetch-cert > public-cert.pem
    

    그다음, 일반 Secret YAML 파일을 kubeseal CLI 툴을 사용하여 암호화합니다.

    # original-secret.yaml (평문 Secret 예시)
    apiVersion: v1
    kind: Secret
    metadata:
      name: my-app-secret
      namespace: default
    data:
      username: dXNlcg==
      password: cGFzcw==
    type: Opaque
    
    # Secret 암호화
    cat original-secret.yaml | kubeseal --cert public-cert.pem --format yaml > sealed-secret.yaml
    

    이렇게 생성된 sealed-secret.yaml 파일은 암호화되어 Git 리포지토리에 안전하게 저장할 수 있습니다. 클러스터 내의 Sealed Secrets 컨트롤러가 이 파일을 감지하고 자동으로 복호화하여 일반 Secret으로 만들어줍니다.

    Sealed Secrets의 작동 원리를 보여주는 시퀀스 다이어그램입니다.

    Sealed Secrets의 작동 원리를 보여주는 시퀀스 다이어그램입니다.

    제가 겪은 트러블슈팅: 권한 문제와 재배포

    이런 설정들을 적용하다 보면 예상치 못한 문제에 부딪히기 마련이죠. 제가 가장 많이 겪었던 ‘삽질’은 바로 RBAC 권한 문제였습니다. Secret에 대한 접근 권한을 너무 강하게 제한했더니, 정작 애플리케이션 파드가 Secret을 읽지 못해서 배포가 실패하는 경우가 많았어요. 에러 메시지에 permission denied나 secret not found가 뜨면 정말 머리아파죠.

    해결책은 간단했습니다. Role과 RoleBinding을 세밀하게 조정하는 것이죠. 특정 네임스페이스의 ServiceAccount(서비스 계정)에 해당 네임스페이스 내의 Secret에 대한 get, list, watch 권한만 부여하도록 했습니다. 그리고 kubectl auth can-i get secrets --as=system:serviceaccount:<namespace>:<serviceaccount-name> 명령어로 실제 권한을 꼼꼼히 확인하는 습관을 들였어요.

    또 하나는 위에서 언급했던 Secret 변경 후 파드 재배포 문제였습니다. Secret만 바꾸고 파드를 재시작하지 않아서 한참을 헤매다가 결국 kubectl rollout restart deployment <deployment-name> 명령어를 날려야 해결되는 걸 보고 허탈했던 기억이 있네요. 자동화 툴을 사용하기 전까지는 배포 스크립트에 반드시 재시작 로직을 포함시키는 것이 중요합니다.

    마무리하며: 안전한 쿠버네티스 운영을 위한 필수 요소

    오늘은 쿠버네티스 Secret 관리의 중요성과 함께, 제가 직접 겪고 배운 민감 데이터 보안 강화 전략 체크리스트를 공유해드렸습니다. 사실 쿠버네티스 Secret은 그 자체로 완벽한 보안 솔루션이라기보다는, 다른 보안 도구들과 함께 사용될 때 비로소 제 역할을 하는 퍼즐 조각이라고 생각합니다.

    정리하자면:

    1. etcd 암호화는 기본 중의 기본!
    2. RBAC로 Secret 접근 권한을 꼼꼼히 관리하기.
    3. Sealed Secrets나 Vault 같은 외부 솔루션으로 보안 강화 및 GitOps 환경 통합.
    4. KMS Provider를 활용한 Secret 볼륨 암호화 고려.
    5. Secret 변경 시 파드 재시작/재배포 잊지 말기.
    6. Secret Rotation으로 주기적인 보안 강화.

    이 체크리스트를 바탕으로 여러분의 쿠버네티스 환경이 더욱 안전해지기를 바랍니다. 민감 데이터는 언제나 최우선으로 보호해야 할 대상이니까요. 다음 글에서는 특정 외부 Secret 관리 솔루션을 더 깊이 파고드는 내용을 다뤄볼까 합니다. 기대해주세요!

    안전한 쿠버네티스 Secret 관리를 위한 핵심 체크리스트 요약 인포그래픽입니다.

    안전한 쿠버네티스 Secret 관리를 위한 핵심 체크리스트 요약 인포그래픽입니다.

  • [Game] ROG Ally에 SteamOS 설치 후기: 윈도우에서 리눅스로 게이밍 환경 전환

    [Game] ROG Ally에 SteamOS 설치 후기: 윈도우에서 리눅스로 게이밍 환경 전환

    ROG Ally에 SteamOS 설치 후기: 윈도우에서 리눅스로 게이밍 환경 전환

    안녕하세요, 13년차 서버실 지킴이, “13년차의 서버실”입니다. 오늘은 제가 최근에 푹 빠져서 삽질 좀 했던 이야기, 바로 ROG Ally에 SteamOS를 설치한 후기를 공유해볼까 합니다. 윈도우 기반의 휴대용 게이밍 PC인 ROG Ally(ROG 앨라이)를 사용하면서 겪었던 불편함과, 이를 해결하고자 리눅스 기반의 SteamOS(스팀OS) 환경으로 전환했던 과정을 솔직하게 풀어볼게요. 혹시 ROG Ally의 윈도우 환경에 지치셨거나, ROG Ally 리눅스 게이밍 환경에 관심 있으신 분들이라면 제 경험이 조금이나마 도움이 될 겁니다.

    처음 ROG Ally를 구매했을 때는 ‘와, 윈도우 기반이라 뭐든 할 수 있겠네!’ 하고 잔뜩 기대했었거든요. 그런데 막상 써보니까, 윈도우가 가볍지 않아서 배터리 효율이 아쉽고, 백그라운드에서 돌아가는 수많은 프로세스 때문에 게임 성능이 들쭉날쭉하더라고요. 게다가 잦은 윈도우 업데이트는 휴대용 기기에서 여간 번거로운 게 아니었습니다. 이런저런 아쉬움이 쌓여가던 차에, 문득 “Steam Deck(스팀 덱)처럼 SteamOS를 설치하면 어떨까?” 하는 생각이 들었죠. 그렇게 저의 ROG Ally SteamOS 마이그레이션(migration) 여정이 시작되었습니다. 꽤나 흥미진진한 삽질의 연속이었지만, 결과적으로는 만족스러운 게이밍 환경을 구축할 수 있었답니다! 🎉

    ROG Ally에 SteamOS를 설치하여 윈도우와 대비되는 휴대용 게이밍 환경을 보여주는 다이어그램

    ROG Ally에 SteamOS를 설치하여 윈도우와 대비되는 휴대용 게이밍 환경을 보여주는 다이어그램

    개념 설명: ROG Ally와 SteamOS, 그리고 HoloISO

    본격적인 설치 후기에 앞서, 핵심 개념들을 간단히 짚고 넘어가겠습니다.

    • ROG Ally (에이수스 ROG 앨라이): ASUS(에이수스)에서 출시한 휴대용 게이밍 PC입니다. 강력한 AMD Ryzen Z1 Extreme 프로세서를 탑재하여 AAA급 게임도 구동할 수 있죠. 기본 OS는 Windows 11(윈도우 11)입니다.

    • SteamOS (스팀OS): Valve(밸브)에서 개발한 Linux(리눅스) 기반의 운영체제입니다. 자사 휴대용 게이밍 기기인 Steam Deck에 최적화되어 있습니다. 게이밍 성능, 빠른 부팅, 배터리 효율성에 강점이 있어요. Steam(스팀) 라이브러리를 위한 Big Picture Mode(빅 픽처 모드)와 유사한 사용자 인터페이스를 제공합니다.

    • HoloISO (홀로ISO): Valve의 SteamOS는 공식적으로 Steam Deck 전용입니다. 하지만 오픈소스 커뮤니티에서는 다른 하드웨어에서도 SteamOS와 유사한 경험을 할 수 있도록 HoloISO라는 비공식 프로젝트를 진행하고 있습니다. 쉽게 말해, SteamOS의 핵심 요소를 일반 PC나 ROG Ally 같은 휴대용 기기에 설치할 수 있도록 만든 배포판이라고 보시면 돼요. 저는 이 HoloISO를 사용하여 ROG Ally에 SteamOS 설치를 진행했습니다.

    이러한 휴대용 게이밍 PC OS 전환은 비공식적인 경로를 택해야 하지만, 윈도우의 무거움에서 벗어나고자 하는 저 같은 사용자들에게는 충분히 매력적인 시도였죠.

    실전 구현: ROG Ally에 HoloISO 설치 단계별 가이드

    이제 제가 직접 겪었던 ROG Ally 리눅스 환경 구축 과정을 단계별로 설명해 드릴게요. 삽질을 줄이기 위한 저의 노하우도 함께 담았습니다.

    1. 사전 준비물 확보

    설치에 필요한 것들을 미리 준비해두면 정말 도움이 됩니다.

    • USB 드라이브: 8GB 이상의 용량. HoloISO 설치 이미지를 구울 거예요.
    • Rufus(루퍼스) 또는 Balena Etcher(발레나 에처): 부팅 가능한 USB를 만들기 위한 도구입니다.
    • USB-C 허브: ROG Ally에 USB 드라이브, 유선 키보드, 마우스를 연결해야 해요.
    • 유선 키보드/마우스: 설치 과정에서 필수입니다. 터치스크린과 Ally의 컨트롤러는 초기 단계에서 작동하지 않을 수 있거든요.
    • HoloISO 이미지 파일: HoloISO 프로젝트의 공식 GitHub 저장소나 커뮤니티에서 제공하는 최신 ISO 파일을 다운로드하세요. (버전은 항상 최신 것을 확인하세요!)

    2. 부팅 USB 만들기

    다운로드한 HoloISO ISO 파일을 Rufus나 Balena Etcher를 이용해 USB 드라이브에 구워요. 이 과정은 일반적인 OS 설치 USB를 만드는 것과 동일합니다.

    # Rufus 사용 예시 (Windows)
    # Rufus를 실행하고, 다운로드한 HoloISO ISO 파일을 선택한 후, 
    # 부팅 가능한 USB 드라이브를 선택하고 '시작' 버튼을 누릅니다.
    

    3. ROG Ally BIOS 설정

    ROG Ally에서 USB로 부팅하려면 BIOS(바이오스) 설정을 변경해야 합니다.

    1. ROG Ally 전원을 끈 상태에서 전원 버튼 + 볼륨 다운 버튼을 동시에 눌러 BIOS로 진입해요.
    2. <code>Advanced Mode(고급 모드)로 들어갑니다.
    3. Security(보안) 탭에서 Secure Boot(보안 부팅)을 Disabled(비활성화)로 설정하세요. 이게 활성화되어 있으면 리눅스 부팅이 안 되더라고요.
    4. Boot(부팅) 탭에서 USB 드라이브를 최우선 부팅 순위로 변경합니다.
    5. Save & Exit(저장 후 종료)를 선택하여 변경사항을 저장하고 재부팅하세요.

    4. HoloISO 설치 진행

    USB로 부팅이 되면 HoloISO 설치 화면이 나타납니다.

    1. 설치 시작 화면에서 Install HoloISO를 선택해요.
    2. 언어, 시간대, 키보드 레이아웃 등을 설정합니다.
    3. 파티션 설정: 여기서 중요한 선택을 해야 해요.
      • Full Disk Erase(전체 디스크 지우기): 기존 윈도우 환경을 완전히 지우고 HoloISO만 설치하는 방법입니다. 가장 깔끔하고 권장하는 방식이에요.
      • Dual Boot(듀얼 부팅): 윈도우와 HoloISO를 함께 사용하는 방법인데, ROG Ally에서는 파티션 관리가 복잡하고 추후 문제가 생길 여지가 많아 초보자에게는 추천하지 않아요. 저는 Full Disk Erase를 선택했습니다.
    4. 사용자 계정 (username, password)을 설정하세요.
    5. 설치가 완료되면 재부팅하라는 메시지가 나오고, USB를 제거한 후 재부팅하면 HoloISO로 부팅돼요.
    ROG Ally에 HoloISO(SteamOS 파생)를 설치하는 과정 중 부팅 USB 선택 및 초기 설정 화면

    ROG Ally에 HoloISO(SteamOS 파생)를 설치하는 과정 중 부팅 USB 선택 및 초기 설정 화면 스크린샷

    5. 초기 설정 및 드라이버 설치

    설치 후 바로 모든 기능이 완벽하게 작동하는 건 아니에요. 여기서부터 진짜 삽질이 시작될 수 있죠. 😅

    1. Steam 클라이언트 로그인: HoloISO 부팅 후 Steam 클라이언트에 로그인해요. Steam Deck과 동일한 사용자 경험을 제공합니다.

    2. 드라이버 및 패치 적용: ROG Ally는 Steam Deck과 하드웨어가 다르기 때문에, Wi-Fi(와이파이), Bluetooth(블루투스), 오디오, 컨트롤러, 자이로 센서 등 일부 드라이버가 제대로 작동하지 않을 수 있어요. 저도 처음에 Wi-Fi가 안 잡혀서 엄청 당황했거든요. ⚠️

      이럴 때는 커뮤니티에서 제공하는 스크립트나 패치를 적용해야 해요. 예를 들어, GitHub에서 “HoloISO ROG Ally fixes” 같은 키워드로 검색하면 커뮤니티 프로젝트들을 찾을 수 있습니다. 터미널(terminal)을 열어 다음처럼 시스템을 업데이트하고 필요한 패치를 적용할 수 있어요. (구체적인 스크립트는 해당 프로젝트의 가이드를 따르세요.)

      # 시스템 업데이트
      sudo pacman -Syu
      
      # 커뮤니티에서 제공하는 드라이버/패치 스크립트 적용 예시
      # GitHub의 해당 프로젝트 저장소에서 명령어를 복사해 실행합니다.
      

    주의사항 및 트러블슈팅: 제가 겪었던 문제들

    ROG Ally SteamOS 환경은 분명 매력적이지만, 비공식적인 경로를 택하는 만큼 감수해야 할 부분들도 있어요. 제가 직접 겪었던 문제들과 해결책을 공유합니다.

    • ⚠️ 공식 지원의 부재: 가장 큰 문제예요. HoloISO는 Valve의 공식 제품이 아니므로, 문제가 발생하면 오직 커뮤니티의 도움에 의존해야 합니다. 새로운 하드웨어 지원이나 버그 수정이 늦어질 수 있어요.

    • 드라이버 문제: 위에서 언급했듯이, Wi-Fi, 블루투스, 오디오, 자이로 센서 등이 제대로 작동하지 않을 수 있습니다. 특히 오디오 드라이버는 저를 꽤나 괴롭혔어요. 커뮤니티의 패치 스크립트가 중요하고, 리눅스 환경에 대한 기본적인 이해가 있다면 트러블슈팅에 정말 도움이 될 거예요.

    • Armoury Crate(아머리 크레이트) 기능 부재: ROG Ally의 핵심 소프트웨어인 Armoury Crate는 윈도우 전용이에요. 팬 속도, TDP(열 설계 전력), 컨트롤러 매핑, 작동 모드 변경 등 ROG Ally의 특수 기능을 SteamOS에서 완벽하게 제어하기 어려워요. 저전력 모드나 터보 모드 전환이 안 되니 답답하더라고요.

      • 해결법: “HandyGCCS” 같은 서드파티 리눅스 툴을 사용하면 일부 기능을 제어할 수 있어요. 하지만 윈도우의 Armoury Crate만큼 완벽하지는 않습니다.
    • 게임 호환성 문제: SteamOS는 Proton(프로톤)을 통해 윈도우 게임을 구동하지만, 모든 게임이 100% 호환되는 건 아니에요. 특히 Easy Anti-Cheat(이지 안티 치트)나 BattlEye(배틀아이) 같은 Anti-cheat(안티 치트) 프로그램이 적용된 온라인 게임들은 구동이 어렵거나 아예 불가능한 경우가 많더라고요. 제가 즐겨 하던 몇몇 온라인 게임은 결국 포기해야 했습니다. 😢

    검증 및 결과: 만족스러운가?

    수많은 삽질 끝에 ROG Ally에 SteamOS 설치를 완료하고, 실제로 게임들을 돌려보니 확실히 장단점이 명확했어요.

    • 성능 향상 및 배터리 효율: 윈도우 대비 OS 자체가 가볍고 백그라운드 프로세스가 적어서 전반적으로 빠릿빠릿한 느낌을 받았어요. 체감상 게임 로딩 속도도 빨라졌고, 배터리 지속 시간도 소폭 개선된 것 같았습니다. 휴대용 게이밍 PC OS로서의 본분에 더 충실해진 느낌이 들었어요.

    • 게이밍 경험: Steam Deck과 유사한 편리한 인터페이스는 정말 큰 장점이에요. 게임 라이브러리에 바로 접근하고, 컨트롤러 매핑도 잘 작동해서 콘솔처럼 편하게 게임을 즐길 수 있었습니다. “이거 진짜 편하더라고요!” 하는 감탄사가 절로 나왔어요.

    • 단점 재확인: 물론 드라이버 문제는 여전히 존재하고, Armoury Crate의 부재는 ROG Ally의 잠재력을 100% 끌어내지 못하는 아쉬움으로 남아요. 온라인 멀티플레이 게임을 즐기는 분들에게는 정말 치명적인 단점일 수 있습니다.

    제 경험을 바탕으로 ROG Ally SteamOS 환경의 장단점을 표로 정리해봤습니다.

    장점 (Pros) 단점 (Cons)
    ✅ 가벼운 OS로 인한 성능 향상 ⚠️ 비공식 OS로 인한 제한적인 지원
    ✅ 향상된 배터리 효율 ❌ 일부 하드웨어 드라이버 문제 (Wi-Fi, 오디오 등)
    ✅ Steam Deck과 유사한 게이밍 UI/UX ❌ Armoury Crate(팬, TDP 등) 기능 부재
    ✅ 빠른 부팅 및 종료 ❌ 안티 치트 게임 호환성 문제
    ✅ 리눅스 기반의 확장성 ❌ 설치 및 유지보수에 기술적 지식 요구
    ROG Ally에서 SteamOS 기반으로 스팀 게임을 실행하는 화면

    ROG Ally에서 SteamOS 기반으로 스팀 게임을 실행하는 화면. 게임 로딩 중이거나 게임 플레이 중인 모습

    마무리: 도전적인 선택의 가치

    ROG Ally에 SteamOS를 설치하는 것은 분명 도전적이지만 매력적인 선택지예요. 윈도우의 편리함을 포기하는 대신, 더 가볍고 게이밍에 최적화된 환경을 얻을 수 있죠. 저처럼 리눅스 환경에 익숙하고, 새로운 기술을 직접 실험해보는 걸 즐기며, 윈도우의 제약에서 벗어나 배터리 효율과 Steam Deck과 유사한 사용자 경험을 원하는 분들이라면 충분히 시도해볼 가치가 있다고 생각해요. 물론, 그 과정에서 겪는 삽질은 각자의 몫이겠지만요! ㅎㅎ

    이번 ROG Ally SteamOS 마이그레이션 경험을 통해, 하드웨어의 잠재력을 최대한 끌어내기 위해 OS를 바꾸는 것이 얼마나 큰 변화를 가져올 수 있는지 다시 한번 느꼈어요. 휴대용 게이밍 PC OS의 선택은 개인의 취향과 활용 목적에 따라 정말 달라질 수 있다는 점도요.

    다음 글에서는 ROG Ally 리눅스 환경에서 에뮬레이션(emulation)을 설정하는 방법이나, Dual Boot(듀얼 부팅)을 위한 좀 더 안정적인 방법을 찾아보는 이야기도 다뤄볼까 합니다. 혹시 이런 경험 있으신가요? 여러분도 ROG Ally에 SteamOS 설치해보실 의향이 있으신가요? 아래 댓글로 여러분의 생각이나 경험을 공유해주세요! 💡

    ROG Ally에서 SteamOS를 사용하는 경험의 장단점을 요약한 인포그래픽

    ROG Ally에서 SteamOS를 사용하는 경험의 장단점을 요약한 인포그래픽