Quản lý tài nguyên trong Kubernetes
Trước khi Kubernetes phổ biến như hiện nay, các ứng dụng thường phải chạy trên các VM và dùng toàn bộ tài nguyên của VM đó. Người vận hành và các lập trình viên cần chọn lựa rất kĩ càng về size của VM dùng để chạy ứng dụng đó. Tuy nhiên với Kubernetes, các pod có thể chạy trên bất kì máy nào. Để làm được việc này ta cần có cách để chia sẻ tài nguyên giữa các pod và đó là lúc ta cần suy nghĩ đến QoS và Resource Quota.
Resource request và limits
Khi tạo pod, ta cần đặt request và limit cho CPU và RAM cho mọi container bên trong.
Ví dụ:
spec:
containers:
- image: k8s/hello-k8s
name: hello-k8s
resources:
requests:
cpu: 100m
memory: 200Mi
limits:
cpu: 200m
memory: 400Mi
Requests: Giá trị dùng để lập lịch. Nó là lượng tài nguyên cần thiết nhỏ nhất mà một container cần để chạy. Các pod sẽ dừng ở trạng thái Pending nếu không có node nào có đủ tài nguyên cần thiết.
Limits: Lượng tài nguyên tối đa node cho phép các container này dùng.
Nếu một container cố gắng dùng quá lượng CPU limit, hệ thống sẽ điều tiết lại (throttle) container đó.
Nếu container cố gắng dùng quá lượng RAM limit, nó sẽ bị terminate và có thể restart lại tùy thuộc vào container restart policy bạn đã định nghĩa.
Các Quality of Service class (QoS)
Một node có thể bị overcommit khi nó chứa pod được lập lịch mà không định nghĩa request hoặc khi tổng limit giữa các pod trên node đó vượt quá lượng tài nguyên khả dụng của node. Trong tình huống này, các pod trên node sẽ cố gắng sử dụng nhiều tài nguyên hơn mức khả dụng của node.
Khi đó node phải chia mức độ ưu tiên cho các container. Các container có thứ tự ưu tiên thấp nhất sẽ bị terminate đầu tiên. Để quyết định mức độ ưu tiên cho các container ta sử dụng QoS class.
Mức độ ưu tiên | Tên class | Định nghĩa |
1 (cao nhất) | Guaranteed | Nếu các limit và request được đặt cho mọi tài nguyên bằng nhau (khác 0). |
2 | Burstable | Nếu các request và limit được đặt cho mọi tài nguyên không bằng nhau (khác 0). |
3 (thấp nhất) | BestEffort | Nếu các request và limit không được đặt cho bất kì tài nguyên nào. |
Nếu lập trình viên không định nghĩa CPU/RAM request và limit, container sẽ bị terminate đầu tiên. Ta nên bảo vệ các pod quan trọng trong các dự án production bằng cách đặt các limit để chúng được phân loại vào Guaranteed. Best-effort và burstable chỉ nên dùng trong các dự án dev.
Project quota và limit ranges
Quản trị viên có thể đặt Project Quota để giới hạn mức độ sử dụng tài nguyên. Điều này tạo ra một tác động: nếu đặt RAM request trong quota thì mọi pod cần đặt RAM request trong định nghĩa của chúng. Pod mới sẽ không được lập lịch và sẽ ở trạng thái Pending nếu nó cố gắng tìm nhiều tài nguyên hơn giới hạn của quota.
Limit range là một policy dùng để giới hạn tài nguyên sử dụng bởi pod hoặc container trong một namespace. Nó có thể:
Đặt request/limit mặc định cho các tài nguyên trong namespace và tự động đưa chúng vào các container trong runtime.
Giới hạn lượng sử dụng tài nguyên của pod hoặc container trong namespace.
Giới hạn lượng request tới PersistentVolumeClaim trong namespace.
Đặt một tỉ lệ giữa request và limit cho một tài nguyên trong một namespace.
Ta cần quản lý tài nguyên của cụm bằng cách theo dõi những gì?
- Tỉ lệ tài nguyên được cấp phát trên tổng tài nguyên khả dụng của cụm
Một ngưỡng cảnh báo tốt là (n-1)/n*100 với n là số lượng node.
Bạn không thể tái phân bổ các workload trong phần còn lại của các node nếu vượt qua ngưỡng này.
- Tỉ lệ sử dụng tài nguyên trong node
OS Kernel sẽ gọi OOMKiller khi lượng sử dụng RAM gặp áp lực trong node.
Khi CPU bị áp lực sẽ dẫn đến các tiến trình bị hạn chế và ảnh hưởng tới hiệu suất của chúng.
Một ngưỡng cảnh báo rằng node này đang có thể gặp vấn đề hoặc sắp đặt tới "Eviction Policies":
- Kiểm tra cài đặt "Eviction Policies". Đảm bảo các cảnh báo đã được kích hoạt trước khi đạt tới ngưỡng eviction-hard.
- CPU, memory request so với dung lượng trong node
Thêm các ngưỡng cảnh báo sau để thông báo khi node có thể không thể cấp phát các pod mới:
Thấp hơn 10% CPU có thể cấp phát cho CPU request.
Thấp hơn 10% RAM có thể cấp phát cho RAM request.
Nếu n-1 node không thể cấp phát cho các pod mới thì ta cần scale up hoặc kiểm tra xem các CPU/RAM request có quá cao hay không.
- Dung lượng ổ cứng trong node
Nếu node hết dung lượng ổ cứng, nó sẽ cố gắng giải phóng không gian của docker và có khả năng pod sẽ bị loại bỏ (evict).
- Lượng CPU và RAM cho mỗi container
Vì Kubernetes giới hạn cho từng container chứ không phải từng pod nên không nhất thiết phải quản lý tài nguyên cho từng pod.
Lý tưởng là các container dùng một lượng tài nguyên tương đương với lượng đã được request. Nếu sử dụng ít hơn request thì sẽ dẫn đến lãng phí tài nguyên và có thể dẫn đến khó cấp phát các pod mới. Trường hợp ngược lại thì sử dụng nhiều tài nguyên hơn khả dụng có thể dẫn đến các vấn đề về hiệu năng.
Kết luận
Việc đảm bảo các request và limit được định nghĩa và kiểm tra trước khi triển khai thực tế là rất quan trọng. Các quản trị viên của cụm có thể tạo một namespace quota để đặt một request và limit tới mọi container của các workload trong namespace. Một cấu hình tốt của các request và limit sẽ giúp ứng dụng ổn định hơn rất nhiều
Các chỉ số sử dụng để theo dõi và cảnh báo sẽ giúp quản trị viên cụm giảm thiểu số lượng tài nguyên lãng phí và tránh các vấn đề về hiệu năng. 🙂