ZeroOps with Auto Remediation for K8S
TL;DR
Trong quá trình vận hành K8s (mà thực ra chỉ là GKE) với vai trò là SRE, mình có phát triển 1 vài tool nhỏ để phục vụ công việc của mình. Hầu hết các tool để giải quyết các vấn đề về cost, automation và đảm bảo độ ổn định cho K8S workload,… . Nhân tiện có chủ đề, mình có dịp kết hợp bộ tool vào thành 1 giải pháp khá hoàn chỉnh
Introduction
Hiện tại, mình đang quản lý một vài K8s Cluster, trong đó có hệ thống data platform đang sử dụng Spark. Với số lượng lớn Spark job chạy hàng ngày và cần monitoring liên tục để đảm bảo tối thiểu số lượng workload/job fail nhất mà vẫn phải đảm bảo cân bằng về cost. Với công việc chỉ có ngồi monitor với fix job fail trông có vẻ nhàm chán, và hệ thống ngày càng scale thì cần có gì đó để thay đổi việc này?
Mình quyết định phát triển 1 hệ thống gọi là “Auto Remediation” để tự động fix một số lỗi cơ bản cần vận hành trong hệ thống data platform và phát triển thêm để hoạt động với các workload khác trên K8S. Hệ thống này ban đầu để xử lý các vấn đề gặp phải về memory đối với workload chạy trên K8S, đặc biệt là lỗi Out-Of-Memory(OOM). Đây cũng có thể coi là 1 phần của bài toán rightsizing cho workload, khi giải quyết được vấn đề này có thể đem lại:
- Giảm infra cost
- Giảm nhân lực vận hành hệ thống
- Giảm số lượng lỗi trên production, đồng thời giảm các chi phí phát sinh khi lỗi xảy ra
- Và mình có thêm thời gian ngủ mỗi ngày 😂
Về tổng quan, Auto Remediation dựa vào log và metrics kết hợp với bộ rule-based classifier để đưa ra các quyết định cụ thể nhắm giải quyết các vấn đề gặp phải. Hệ thống có thể giải quyết được rất nhiều case khác nữa khi phát triển thêm rule-based classifier từ SRE để tự động hóa 1 phần hệ thống. Nội dung tiếp theo mình sẽ giới thiệu vài tool nhỏ mà mình phát triển để giải quyết từng phần.
K8S workload rightsizing
Từ năm 2023, khi bắt đầu với công việc làm SRE, mình đã phát triển tool này để giải quyết vấn đề recommend cho K8S workload gọi là GRR( GKE resource recommendation - vì mình phát triển cho GKE).
Bạn có thể coi GRR hoạt động như VPA nhưng được mình custom lại cách tính toán recommend dựa vào metrics nhằm phù hợp hơn với nhu cầu sử dụng và update thêm 1 vài tính năng để đảm chạy ổn định khi hệ thống scale, tính chính xác hơn phần memory. Tool này mình có đem đi trình bày tại Viet-OpenInfra 2023, so với version hiện tại, mình có update thêm để xác định thêm phần memory cần để start pod (phục vụ cho Java app)
Tuy có thể giải quyết được vấn đề workload rightsizing nhưng 1 ngày nào đó pod cần thêm memory cũng hơi khó để rollout lại.
OOM Killer
Lỗi Out-Of-Memory(OOM) là lỗi khá phổ biến đối với chúng ta khi dùng K8S. Để giới hạn lượng memory của container sử dụng trong K8S, người dùng có thể sử dụng resource limit
để. Nhưng nếu memory usage của container vượt limit → Lỗi OOMKiled xuất hiện và app của bạn sẽ bị downtime.
Vậy set limit cao cao chút để không bị OOM là được, khi worker node bị memory pressure → evict pod là được, quá đơn giản 🙂
Thật không may là đám Spark app chạy trên K8S khi submit job sẽ set memory request = memory limit, do đó việc bạn set memory limit đồng thời cũng làm tốn thêm resource. Mà chắc gì 1 ngày đẹp trời nào đó, lượng data tăng đột biến thì config ban đầu cũng không còn đúng nữa và vẫn bị OOM thôi. Ngoài ra app Java chạy trên K8S thường config -XX:MaxRAMPercentage
để khai báo max Heap theo memory limit.
Vậy là ngoài đảm bảo memory usage của container không được chạm resource limit còn phải lo thêm Heap memory không vượt ngưỡng max, dính 1 trong 2 case là container restart rồi.
Để giải quyết vấn đề này, mình có phát triển tool để chuyên đi xóa pod khi memory usage của container gần chạm ngưỡng limit và cũng support Java Spring khi Heap memory gần chạm ngưỡng max. Mình tận dụng luôn K8S metrics server để lấy metrics của container memory, đối với Java Spring bạn cần enable thêm Spring Boot Actuator. Thông tin về tool: https://github.com/phamngocsonls/k8s-oom-killer
Auto Remediation
Hơi lan man về 2 tool 😄, khi kết hợp cả 2 lại và thêm 1 vài luồng mới để để tích hợp với hệ thống hiện tại thành 1 luồng khá đầy đủ như dưới đây:
Architecture
Về mặt kiến trúc của hệ thống hiện tại, mình đang sử dụng trên Google Cloud nên sẽ tận dụng các dịch vụ của Google Cloud. Mình có 2 GKE cluster:
- GKE cluster 1: Triển khai các workload cơ bản, trên GKE cluster này được cài OOM Killer để kiểm soát memory limit của container, tránh bị lỗi OOM xảy ra.
- GKE cluster 2: Triển khai Spark cho hệ thống data platform
Rule Execution Engine: Nhận trigger từ Pub/Sub topics được route từ log của các GKE cluster, sau đó xử lý với bộ rule có sẵn. Rule có thể được phát triển từ nhiều SRE tùy thuộc vào các case cụ thể. Rule nhằm phân loại log bao gồm source đến từ đâu, nội dung log và các action cụ thể. Một số lỗi có thể không cần làm gì hoặc cần tăng resource. Sau khi xử lý, kết quả sẽ được đẩy vào database Operational storage. VD một case cụ thể: Log đẩy về có thể là log pod bị xóa bởi tool OOM Killer, trong trường hợp này mình sẽ log lại để luồng tiếp theo xử lý (Nếu việc này lặp lại nhiều có thể cần nâng memory cho workload này.
Config Service: Chứa thông tin về recommend resource cho các workload, được lấy từ tool K8S workload rightsizing
Pensive: Được trigger định kì từ từ Cloud Scheduler, Pensive đọc thông tin từ Operational storage để đưa ra quyết định cụ thể. Nếu workload cần tăng resource, Pensive gọi tới Config Service để lấy config mới cho service và commit vào GitOps repo để Argo CD thực hiện rollout với cấu hình mới. Đối với Apache Spark job, Airflow sẽ call định kì tới Pensive lấy resource config mới cho Spark job.
Tổng kết
Auto Remediation có thể giải quyết được nhiều vấn đề phát sinh khi vận hành K8S trong tương lai khi SRE tham gia phát triển bộ Rule Engine để ngày càng hoàn thiện khi hệ thống ngày càng scale và phát sinh ra nhiều lỗi lặp đi lặp lại. Thời gian đầu phát triển có thể gặp nhiều false positive ảnh hưởng tới production nên mọi người có thể xem xét trước khi triển khai.
All rights reserved