Volterra에서 SRE 팀의 업무는 글로벌 SaaS 기반 에지 플랫폼을 운영하는 것입니다. 우리는 다양한 상태(예: 온라인, 오프라인, 관리자 중단 등)에서 많은 수의 애플리케이션 클러스터를 관리하는 데 있어 다양한 과제를 해결해야 하며, 이를 위해 GitOps를 사용하여 선언적 풀 기반 모델과 Kubernetes 생태계를 활용하고 도구를 활용합니다.
이 블로그에서는 다음 내용을 설명합니다.
GitOps를 사용하여 대규모 인프라(물리적 또는 클라우드 호스트) 및 K8s 클러스터를 효과적으로 관리하고 모니터링합니다.
최근 샌디에이고에서 열린 Cloud Native Rejekts에서 제가 한 강연에서도 다루었던, 규모에 따른 교훈(3,000개의 엣지 사이트)을 더 자세히 살펴보겠습니다.
위의 아키텍처 다이어그램(그림 1)은 RE와 CE 간의 논리적 연결을 보여줍니다. 각 CE는 가장 가까운 RE에 중복(IPSec 또는 SSL VPN) 연결을 설정합니다.
약 2년 전 플랫폼을 설계하기 시작했을 때, 제품 팀에서는 다음과 같은 과제를 해결해 달라고 요청했습니다.
고도로 분산된 시스템을 운영하는 데 필요한 요구 사항과 과제를 고려하여 다운스트림 문제를 줄이기 위해 SRE 팀이 따라야 할 몇 가지 원칙을 정하기로 했습니다.
에지 사이트 수명 주기 관리의 일환으로 호스트 OS 프로비저닝, 기본 구성(예: 사용자 관리, 인증 기관, 대용량 페이지 등), K8s 실행, 워크로드 배포, 진행 중인 구성 변경 관리 등의 문제를 해결해야 했습니다.
우리가 고려했지만 결국 거부한 옵션 중 하나는 KubeSpray+Ansible(OS 관리 및 K8s 배포)과 Helm/Spinnaker(워크로드 배포)를 사용하는 것이었습니다. 우리가 이를 거부한 이유는 이를 위해 오픈소스 도구 2~3개를 관리하고, 우리의 요구 사항을 충족하기 위해 상당한 수정을 해야 하기 때문이었습니다. 에지 클러스터 자동 확장, 보안 TPM 모듈 지원, 차등 업그레이드 등 더 많은 기능을 추가하면서 요구 사항이 계속 증가했습니다.
우리의 목표는 단순함을 유지하고 OS에서 직접 실행되는 구성 요소의 수(Kubernetes 외부)를 최소화하는 것이었기 때문에 Volterra Platform Manager(VPM)라는 가벼운 Golang 데몬을 작성하기로 했습니다. 이것은 OS에서 유일한 systemd Docker 컨테이너이며 다음과 같은 많은 기능을 수행하는 스위스 군용 칼 역할을 합니다.
VPM은 설치, 업그레이드, 패치, 구성 등 호스트 운영 체제의 수명 주기를 관리하는 역할을 합니다. 구성해야 할 측면이 많이 있습니다(예: hugepages 할당, /etc/hosts 등)
Kubernetes 매니페스트에 대한 수명 주기를 제공하는 관리입니다. Helm을 사용하는 대신, 우리는 VPM에 통합한 K8s client-go 라이브러리를 사용하기로 결정했고, 이 라이브러리의 여러 기능을 사용했습니다.
낙관적 = 리소스를 만들고 상태를 기다리지 않습니다. 이는 실제 Pod가 성공적으로 시작되는지 알 수 없는 Kubernetes apply 명령과 매우 유사합니다.
비관적 = Kubernetes 리소스 상태를 기다립니다. 예를 들어, 배포는 모든 Pod가 준비될 때까지 기다립니다. 이는 새로운 kubectl wait 명령과 유사합니다.
K8s 매니페스트와 관련된 구성 외에도 API를 통해 다양한 Volterra 서비스를 구성해야 합니다. 한 가지 예가 IPsec/SSL VPN 구성입니다. VPM은 글로벌 제어 평면에서 구성을 수신하여 개별 노드에 프로그래밍합니다.
이 기능을 사용하면 원격으로 상자를 원래 상태로 재설정하고 전체 설치 및 등록 과정을 다시 수행할 수 있습니다. 콘솔/물리적 접근이 필요한 사이트를 복구하는 데 매우 중요한 기능입니다.
K8의 수명 주기 관리가 많은 사람들에게 중요한 논의 주제인 것처럼 보일 수 있지만, 저희 팀에서는 전체 작업량의 40~50%에 불과할 것입니다.
클라우드, 온프레미스 또는 노마딕 엣지 등 모든 위치에서 엣지 사이트를 제로터치로 프로비저닝하는 것은 중요한 기능입니다. 개별 사이트에 접근할 수 있을 것으로 기대할 수 없고, 개별 사이트를 설치하고 관리하기 위해 많은 Kubernetes 전문가를 배치하고 싶지 않기 때문입니다. 수천 명까지 확장할 수 없습니다.
다음 다이어그램(그림 2)은 VPM이 새로운 사이트를 등록하는 과정에 어떻게 관여하는지 보여줍니다.
보시다시피, 전체 프로세스가 완전히 자동화되어 사용자는 세부 구성에 대해 알 필요가 없고 수동 단계를 실행할 필요도 없습니다. 전체 장치를 온라인 상태로 전환하고 고객 앱과 요청을 처리할 준비를 하는 데 걸리는 시간은 약 5분입니다.
업그레이드는 우리가 해결해야 할 가장 복잡한 문제 중 하나였습니다. 에지 사이트에서 무엇이 업그레이드되는지 정의해 보겠습니다.
에지 사이트에 업데이트를 전달하는 데 사용할 수 있는 알려진 방법은 두 가지가 있습니다.
업그레이드에 대한 우리의 목표는 표준 휴대전화 업그레이드와 마찬가지로 단순성과 안정성을 극대화하는 것이었습니다. 또한 업그레이드 전략은 다른 고려 사항도 충족해야 합니다. 업그레이드 컨텍스트는 사이트 운영자에게만 해당될 수도 있고, 연결 문제로 인해 장치가 오프라인이거나 잠시 사용할 수 없는 상태일 수도 있습니다. 이러한 요구사항은 풀 방식을 사용하면 더 쉽게 충족할 수 있었기 때문에 우리는 우리의 요구사항을 충족시키기 위해 풀 방식을 채택하기로 결정했습니다.
또한 SRE 팀에 Kubernetes 클러스터, 워크플로 및 감사 변경 사항을 관리하기 위한 표준 운영 모델을 제공하기 쉽기 때문에 GitOps를 선택했습니다.
수천 개 사이트의 확장 문제를 해결하기 위해 우리는 그림 3에 표시된 SRE 아키텍처를 고안했습니다.
먼저, Git을 상태나 매니페스트를 저장하는 데만 사용하는 것이 아니라는 점을 강조하고 싶습니다. 그 이유는 우리 플랫폼이 K8s 매니페스트뿐만 아니라 진행 중인 API 구성, K8s 버전 등도 처리해야 하기 때문입니다. 우리의 경우, K8s 매니페스트는 전체 선언적 구성의 약 60%를 차지합니다. 이러한 이유로 우리는 이를 기반으로 우리만의 DSL 추상화를 개발해야 했고, 이는 git에 저장되었습니다. 또한 git은 API나 매개변수 병합 기능을 제공하지 않기 때문에 SRE를 위해 추가 Golang 데몬을 개발해야 했습니다. 구성 API, 실행자 및 VP 컨트롤러.
SaaS 플랫폼을 사용하여 고객 엣지에서 새로운 소프트웨어 버전을 릴리스하는 워크플로를 살펴보겠습니다.
전체 워크플로우의 데모는 여기에서 볼 수 있습니다:
이전 섹션에서는 엣지 사이트의 수명 주기를 배포하고 관리하는 데 툴을 사용하는 방법을 설명했습니다. 설계의 유효성을 검증하기 위해 우리는 3,000개의 고객 에지 사이트가 있는 대규모 환경을 구축하기로 결정했습니다(그림 4 참조).
우리는 Terraform을 사용하여 AWS, Azure, Google과 자체 온프레미스 베어 메탈 클라우드에서 3,000개의 VM을 프로비저닝하여 규모를 시뮬레이션했습니다. 모든 VM은 지역 에지 사이트(일명 PoP)에 중복 터널을 구축한 독립적인 CE(고객 에지 사이트)였습니다.
아래 스크린샷은 SRE 대시보드에서 가져온 것이며, 원의 크기로 표현된 위치에 있는 에지 번호를 보여줍니다. 스크린샷을 찍을 당시 약 2,711개의 건강한 에지 사이트와 356개의 건강에 해로운 에지 사이트가 있었습니다.
확장 과정의 일환으로 우리는 소프트웨어 데몬을 수정해야 하는 구성 및 운영 측면에서 몇 가지 문제를 발견했습니다. 또한 클라우드 공급업체와 관련하여 여러 문제에 부딪혀 여러 지원 티켓이 개설되기도 했습니다. 예를 들어 API 응답 지연, 단일 지역에서 500개가 넘는 VM을 확보할 수 없음 등이 있습니다.
분산 시스템 전반의 관찰성은 시스템을 확장함에 따라 훨씬 더 큰 과제에 직면하게 되었습니다.
처음에는 메트릭의 경우 Prometheus 연합으로 시작했습니다. 즉, 글로벌 제어에 있는 중앙 Prometheus가 지역 에지(RE)에 있는 Promethei를 연합하여 서비스 메트릭을 스크래핑하고 연결된 CE에서 메트릭을 연합합니다. 최상위 수준의 Prometheus는 경고를 평가하고 추가 분석을 위한 메트릭 소스 역할을 했습니다. 우리는 이 접근 방식의 한계에 빠르게 도달했습니다(약 1000명의 CE). 그리고 증가하는 CE 수의 영향을 최소화하려고 노력했습니다. 우리는 히스토그램과 기타 고차수 지표에 대해 미리 계산된 시리즈를 생성하기 시작했습니다. 이를 통해 하루나 이틀을 절약할 수 있었지만 그 후에는 메트릭을 위한 허용 목록을 사용해야 했습니다. 결국, 우리는 CE 사이트별로 시계열 지표의 수를 약 60,000개에서 2,000개로 줄일 수 있었습니다.
결국, 3000개 CE 사이트를 넘어 확장을 계속하고 여러 날 동안 프로덕션에서 운영한 결과, 이 방식은 확장성이 없다는 점이 분명해졌고 모니터링 인프라를 다시 고려해야 했습니다. 우리는 최상위 Prometheus(전역 제어)를 제거하고 각 RE의 Prometheus를 두 개의 별도 인스턴스로 분할하기로 결정했습니다. 한 사람은 로컬 서비스 메트릭을 스크래핑하는 일을 맡고, 두 번째 사람은 CE 메트릭을 통합하는 일을 맡습니다. 둘 다 알림을 생성하고 측정 항목을 Cortex의 중앙 저장소로 푸시합니다. Cortex는 분석 및 시각화 소스로 사용되며 핵심 모니터링 알림 흐름의 일부가 아닙니다. 우리는 Thanos와 M3db 등 여러 가지 중앙 집중형 메트릭 솔루션을 테스트했으며, Cortex가 우리의 요구 사항에 가장 적합하다는 것을 발견했습니다.
다음 스크린샷(그림 7)은 3000개 엔드포인트에서 prometheus-cef를 스크래핑하는 데 사용되는 메모리 소비량을 보여줍니다. 흥미로운 점은 29.7GB의 RAM이 소모된다는 점인데, 이는 실제로 시스템 규모에 비해 그렇게 많은 것은 아닙니다. 스크래핑을 여러 개로 분할하거나 Cortex에 대한 원격 쓰기를 엣지 자체로 직접 옮기면 더욱 최적화할 수 있습니다.
다음 스크린샷(그림 8)은 이 규모에서 Cortex 인제스터(최대 19GB RAM)와 배포자에 얼마나 많은 메모리와 CPU 리소스가 필요했는지 보여줍니다. Cortex의 가장 큰 장점은 수평적 확장성으로, 수직적으로 확장해야 하는 Prometheus와 달리 더 많은 복제본을 추가할 수 있습니다.
CE와 RE의 로깅 인프라의 경우 노드당 Fluentbit 서비스를 사용하여 서비스 및 시스템 로그 이벤트를 수집하고 이를 연결된 RE의 Fluentd로 전달합니다. Fluentd는 RE에 있는 ElasticSearch로 데이터를 전달합니다. ElasticSearch의 데이터는 Elastalert에 의해 평가되고 Alertmanager 알림을 생성하기 위한 규칙이 설정됩니다. 우리는 Prometheus가 생성하는 것과 동일한 라벨이 있는 알림을 생성하기 위해 Elastalert에서 Alertmananger까지 맞춤 통합을 사용하고 있습니다.
모니터링 여정의 핵심 포인트:
- 처음에는 CE당 약 50,000개의 시계열이 있었고 평균 15개의 레이블이 있었습니다.
- CE당 평균 2000으로 최적화했습니다.
메트릭 이름에 대한 간단한 while 목록 및 레이블 이름에 대한 black 목록
- 중앙화된 Prometheus는 모든 RE 및 CE의 Prometheus를 스크랩했습니다.
- 서기 1000년경에는 측정항목의 양을 관리하는 것이 더 이상 지속 불가능해졌습니다.
- 현재 우리는 각 RE에 Prometheus를 두고 있으며(연결된 CE의 Promethei에 연합) RW는 Cortex에 있습니다.
- 분산 로깅 아키텍처
- 각 노드의 수집기인 Fluentbit는 RE의 Fluentd(집계기)로 로그를 전달합니다.
- ElasticSearch는 단일 Kibana 인스턴스에서 로그를 쿼리하기 위해 원격 클러스터 검색을 사용하여 모든 RE에 배포됩니다.
이 블로그를 통해 전 세계에 배포된 수천 개의 엣지 사이트와 클러스터를 관리하는 데 고려해야 할 사항에 대한 통찰력을 얻을 수 있기를 바랍니다. 초기 설계 요구 사항의 대부분을 충족하고 검증할 수 있었지만, 아직도 많은 개선 사항이 우리 앞에 있습니다...