원클릭 homelab 구축 3 - 자동화/돌아보기

Byeonghoon Yoo·2022년 8월 6일
1

homelab 구축

목록 보기
3/3
post-thumbnail

이 시리즈는 개인적으로 구축한 Kubenetes cluster의 구축 과정과 대략적인 구조를 소개하고, 어떻게 원클릭으로 클러스터를 구축했는지 간단하게 설명할 예정입니다. 구현 디테일은 레포지토리에 점진적으로 문서화할 예정이며, 이 시리즈에서는 멀리서 봤을 때의 구조와 그렇게 구현된 이유, 제가 고민했던 포인트들을 설명할 예정입니다.

이 포스트에서는 2편에서 설명한 클러스터를 어떻게 원클릭으로 구축하게 만들었는지와, 1편에서 정의한 목적을 달성했는지 측정과 함께 비용도 살펴보겠습니다.

  • 1편: 목적과 사연
  • 2편: 구조
  • 3편: 자동화/돌아보기

원클릭 구축을 향하여

재구축을 자동화 하려면 크게 Provisioning, Cluster setup, 서비스 배포 3 구간을 자동화 해야한다.

  1. Provisioning

Cloud라면 Terraform이 해주는 일과 정확히 일치한다. 내가 원하는 인프라 상태를 적어주면 그걸 자동으로 만들어낸다.
하지만 backbone cluster처럼 물리 기계를 가질 경우 Terraform으로 초기화가 어렵다. Cloud는 하나의 API로 OS가 설치된 VM을 받아낼 수 있지만, 물리 기계는 직접 boot device를 만들고 연결한 이후에 각종 OS 설치 옵션들을 선택한 이후에야 완료되기 때문이다.
이걸 해결하기위해 PXEWOL이 존재한다. WOL은 LAN을 통해 원격으로 서버 전원을 킬 수 있도록 해주는 기능이고, PXE는 부팅할 때 특정 이미지를 주입할 수 있는 기능이다. LAN과 전원이 연결 되어있는 물리 노드를 WOL로 전원을 키고 PXE로 OS 설치 이미지를 주입해주면 내가 원하는 OS가 해당 노드에 설치되도록 만들 수 있다.
내 homelab에서는 WOL+PXE는 아직 구현하지 않았다. 다른 자동화에비해 사전 조건이 명확하고 자동화로 얻는 이점이 덜해서 빼놓은 상태이지만 추후에는 추가해보고싶다. 때문에 prod cluster 재구축은 완전히 자동이지만 backbone cluster는 2단계인 Cluster setup부터 자동화 되어있다.

  1. Cluster setup

가장 쉬운 구간이다. 네트워크를 연결해서 노드간 통신이 가능한 상태를 만들고, Kubernetes를 설치해서 GitOps가 가능한 상태를 만드는것이 목적이다. 크게 어렵지 않기 때문에 bash script같은걸 만들 수도 있지만 좀 더 portable하고 idempotent하기 위해서 Ansible을 사용했다. 쉽게 말하면 bash script의 고급 버전이라고 할 수 있다. 모든 노드의 주소와 ssh 접근 secret을 넣어주고, 노드에 어떤 앱을 설치할지 선언적으로 정의한 파일을 넣어주면 해당 노드들에 선언한 상태가 되도록 만들어준다.
내 homelab에서는 기본적인 Wireguard network를 구성한 이후에 k3s를 설치해서 Kubernetes cluster를 구축한다.

  1. 서비스 배포

위에서 설명한 GitOps 패턴인 ArgoCD를 사용하면 쉽게 달성 가능하다. 특히 공식 문서에도 나와있든 App of Apps 패턴을 사용하면 원클릭 구축을 쉽게 하면서, 이후에도 항상 git으로만 관리할 수 있도록 만들어준다. 재구축이 쉬우려면 모든 변경사항을 기록해야 나중에 그대로 다시 만들 수 있는데, App of Apps 패턴을 사용하면 현재의 상태 변경과 변경사항의 기록이 한번에 이뤄진다는 큰 장점이 있다.


Secret 다루기

원클릭 구축에서 가장 어려웠던것은 2편에서 언급했듯 Secret이었다. External-DNS같은 Pod이 Cloudflare처럼 외부 서비스에 요청을 보내려면 인증이 필수이고, 인증을 위해서는 API key가 필수이다. 2편에서는 Secret 또한 상태이기 때문에 Stateless한 원클릭 재구축을 위해선 외부로 떼어내야함을 설명했다.

일반적인 Secret 주입 과정

일단 원클릭을 생각하지 않고 우리가 수동으로 API key를 클러스터에 주입할 때 어떤 과정을 거치는지 살펴보자.

  1. 내가 원하는 Application이 필요한 외부 서비스가 무엇인지와 어떤 인증 방법과 권한을 필요로 하는지 확인한다.
  2. 그 외부 서비스에 로그인한다.
  3. Application이 원하는 권한을 만족하는 인증 토큰을 획득한다.
  4. 인증 토큰을 k8s의 Secret resource로 만든다.

각각을 어떻게 자동화할 수 있을까?

Secret 주입 자동화하기: 1 요구사항 확인

1번은 당연하게도 관리자가 할 수 밖에없다.

Secret 주입 자동화하기: 2, 3번

만약 해당 외부 서비스가 Terraform을통해 권한이 설정된 인증 토큰을 만들어낼 수 있다면, Terraform으로 두 과정을 자동화할 수 있다. 하지만 이게 안되는 경우가 있는데, 내가 경험했던 대표적인 예시는 Cloudflare의 Origin CA Key를 가져오는것이다. 이 경우는 어쩔 수 없이 수동으로 조회해야한다. 하지만 다행히 후자는 드물다.
그렇다면 Terraform은 어떻게 외부 서비스에 접근해서 인증 토큰을 만들어낼까? 이것도 결국 인증 토큰이 있어야 가능하고, 이것을 자동화할 순 없다.
정리하면, 대부분의 경우 Terraform으로 인증 토큰을 생성해낼 수 있기 때문에 개입 없이 인증 토큰을 만들어낼 수 있다. 하지만 Terraform이 외부 서비스에 접근하려면 인증 토큰이 필요하고, 이건 원클릭 구축 이전에 사람이 직접 취득해야한다. 결국 인증 토큰 생성을 위한 인증 토큰 하나만 수동으로 얻어놓으면 그 이후 모든 과정을 자동화할 수 있다.

Secret 주입 자동화하기: 4번

2편에서 설명한것처럼 External-Secrets를 사용했다. 요약하면 GitOps의 동작 방식과 동일하다, 관리자가 직접 클러스터에 secret을 채워넣는게 아니라 외부 저장소에 놓기만 하면 클러스터가 이것을 가져간다.

Secret의 의존성 그래프

위에서 설명한 자동화방법을 구현했을 때 어떤 의존성이 생기는지 설명한다. A -> B는 A가 B에 의존한다는 의미이며, B가 있어야 A가 동작한다는 의미이다.
위에서 설명한것처럼 Terraform이 직접 Cloud provider들에 접근해서 필요로하는 인증 토큰을 생성해낸다. 해당 provider들에 접근하기위한 인증 토큰은 Terraform Cloud의 Variables에 사람이 직접 기록해야한다.

Terraform 코드

isac322/homelab 레포에서 확인할 수 있다. vars.tf를 보면알 수 있듯, 최소한으로 각 Cloud provider들에 접근할 수 있는 인증 데이터들만 받고있다.


목적 달성 체크

목적 1 - (상용에 근접하는) 아주 높은 가용성

가용성이 필요한 모든 서비스는 HA로 구성된 prod cluster에 배포해서 달성했다. cloud이기 때문에 집의 정전이나 사람의 실수, 이사 등등 다양한 이유로 가용성을 해치는 일에서 벗어날 수 있다.

목적 2 - Kubernetes 클러스터

달성

목적 3 - 구축 / 재구축이 버튼 하나 수준으로 간단

자동화를 3단계로 나눠서 각 단계에 맞는 자동화 도구를 사용했고, 현재 homelab은 거의 이 목적을 달성했다.

목적 4 - 계정과 권한만 있으면 특정 기기에 종속되지 않은 배포

git만 수정하면 두 클러스터와 인프라 모두 상태 변경이 가능하기 때문에 달성했다.

목적 5 - 상태 모니터링 / 알림 가능

Prometheus와 Grafana가 구축되어있지만 Alert를 받고있지 않아서 달성하지 못한 상태이다. 우선 자동화를 완성한 이후에 하나씩 달성할 예정이다.

목적 6 - 신뢰성있는 저장소

이번 시리즈에서 설명하진 않지만 Kubernetes 외부에 3개의 HDD로 ZFS를 사용해서 RAID를 구성했고, HDD 하나까지는 죽어도 모든 데이터를 복구할 수 있으며, 자연적으로 변조되는 데이터조차 자동으로 복구하는 관리 기능을 갖추고 있다. 사실 Kubernetes 내부에서도 비슷하게 구현할 수 있는데, state 덩어리인 storage를 Kubernetes cluster에 넣으면 Secret과 마찬가지로 원클릭 재구축에 큰 걸림돌이 된다.

목적 7 - (상용에 근접하는) 보안

개인 데이터 관련된 부분은 Wireguard를 VPN으로 사용해서 접근을 막았다. backbone cluster와 ZFS 저장소 전체를 하나의 UDP 포트로 서빙하기 때문에 취약점을 최소로했다. 하지만 보안은 항상 확신할 수 없어서 지속적으로 더 개선할게 있는지 높은 우선순위로 학습중이다.


비용

현재 월마다 정기적으로 지불하는 비용은 1700원 미만이다. (!)
도메인을 유지하기위해 Cloudflare에 연 $8정도의 비용과, 서버 2대를 집에서 돌릴 때의 전기세 900원 미만이 들어가고, 클라우드를 비롯한 각종 서비스에는 전혀 비용을 지불하지 않고있다. Oracle Free tier에서 정말 파격적인 무료 서비스를 제공하기 때문에 이것만 잘 사용해도 무료로 클러스터를 만들어볼 수 있다.
다만 집에 직접 구축한 기기들은 초기 비용이 필요하다. 서버 기기로 어떤것을 사용하느냐에따라 비용은 천차만별이지만, 나는 현재 Odroid N2+ 2대를 backbone 클러스터의 노드로 쓰고있다. 전원과 메모리까지 다 합치면 노드로만 34만원정도 사용했다. 여기에 저장소로 쓰인 HDD도 비용에 포함해야하는데, 나의 경우 집에 있었던 오래된 HDD를 써서 비용을 측정하기 어렵다. 사실 첫 homelab을 만든지 벌써 3년정도 됐고 Raspberry Pi zero, Raspberry Pi 4, Odroid C4를 구매 후 지금 상태에 정착했기 때문에 총 비용은 60~70만원 정도일 것 같다.
나의 경우 실물 기기로도 클러스터를 만들고 싶었기 때문에 돈을 투자했지만, Oracle Free tier가 워낙 좋기 때문에 클러스터를 하나로 줄이고 역할을 합치면 도메인 비용만 내고도 클러스터를 운영할 수 있다.
초기에 큰 기기 비용을 내서라도 클라우드를 쓰지 않은것은 의도된것이었는데, 첫번째 목적인 고가용성을 위해서는 redundancy가 필수고 이걸 클라우드로 구현하려면 비용이 몇배가 되기 때문이다.

그 후..

첫 homelab을 만든 이후 3년동안 경험을 통한 목표 설정과 고민 포인트들이 다양했기에 3편의 포스트에는 다 담지 못했다. 대부분은 코드에 그 고민들이 녹여있다고 생각하지만 그러지 못한 부분들은 레포의 위키에 차근차근 추가할 예정이다. 예를들면, micro-k8s와 k3s와 kubeadm을 설치해보고 비교했던것, 초반에 저비용으로 고가용성을 위한 로드 밸런싱을 어떻게 구현하는지 고민했었고, 여러 대안들을 살펴보다가 결국 Round-robin DNS로 정착했던 결정 같은것들이다.
또 위의 달성 체크에서 볼 수 있듯 아직 모든 목표를 달성하지 못했다. 처음 시작했을 땐 Docker Swarm은 물론 Kubernetes의 k는 조차 몰랐기 때문에, 남아있는 작업들 또한 모르는것 투성이겠지만 느리려도 천천히 하나씩 뽀개겠다.

0개의 댓글