Xin chào tất cả mọi người! Hôm nay, chúng tôi muốn chia sẻ kinh nghiệm sử dụng Google Kubernetes Engine để quản lý các cụm Kubernetes của chúng tôi. Chúng tôi đã sử dụng nó trong ba năm gần đây nhất trong quá trình sản xuất và hài lòng rằng chúng tôi không còn phải lo lắng về việc tự mình quản lý các cụm này nữa.
Hiện tại, chúng tôi có tất cả các môi trường thử nghiệm và cụm cơ sở hạ tầng duy nhất dưới sự kiểm soát của Kubernetes. Hôm nay, chúng tôi muốn nói về việc chúng tôi đã gặp sự cố như thế nào trong cụm thử nghiệm của mình và chúng tôi hy vọng bài viết này sẽ tiết kiệm thời gian và công sức cho người khác như thế nào.
Chúng tôi phải cung cấp thông tin về cơ sở hạ tầng thử nghiệm của mình để hiểu đầy đủ vấn đề của mình. Chúng tôi có hơn năm môi trường thử nghiệm cố định và đang triển khai môi trường cho các nhà phát triển theo yêu cầu. Số lượng mô-đun vào các ngày trong tuần đạt 6000 vào ban ngày và tiếp tục tăng. Vì tải không ổn định nên chúng tôi đóng gói các mô-đun rất chặt chẽ để tiết kiệm chi phí và bán lại tài nguyên là chiến lược tốt nhất của chúng tôi.
Cấu hình này hoạt động tốt cho chúng tôi cho đến một ngày khi chúng tôi nhận được cảnh báo và không thể xóa không gian tên. Thông báo lỗi chúng tôi nhận được liên quan đến việc xóa không gian tên là:
$ kubectl delete namespace arslanbekov Error from server (Conflict): Operation cannot be fulfilled on namespaces "arslanbekov": The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system.
Ngay cả khi sử dụng tùy chọn buộc xóa cũng không giải quyết được sự cố:
$ kubectl get namespace arslanbekov -o yaml apiVersion: v1 kind: Namespace metadata: ... spec: finalizers: - kubernetes status: phase: Terminating
Để giải quyết vấn đề không gian tên bị kẹt, chúng tôi đã làm theo hướng dẫn . Tuy nhiên, giải pháp tạm thời này không phải là lý tưởng vì lẽ ra các nhà phát triển của chúng tôi có thể tạo và xóa môi trường của họ theo ý muốn bằng cách sử dụng trừu tượng hóa không gian tên.
Quyết tâm tìm ra giải pháp tốt hơn, chúng tôi quyết định điều tra thêm. Cảnh báo chỉ ra một vấn đề về số liệu mà chúng tôi đã xác nhận bằng cách chạy một lệnh:
$ kubectl api-resources --verbs=list --namespaced -o name error: unable to retrieve the complete list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to handle the request
Chúng tôi đã phát hiện ra rằng nhóm máy chủ số liệu đang gặp lỗi hết bộ nhớ (OOM) và lỗi hoảng loạn trong nhật ký:
apiserver panic'd on GET /apis/metrics.k8s.io/v1beta1/nodes: killing connection/stream because serving request timed out and response had been started goroutine 1430 [running]:
Lý do là do giới hạn tài nguyên của nhóm:
Vùng chứa gặp phải các vấn đề này do định nghĩa của nó, như sau (khối giới hạn):
resources: limits: cpu: 51m memory: 123Mi requests: cpu: 51m memory: 123Mi
Vấn đề là vùng chứa chỉ được phân bổ 51m CPU , gần tương đương với 0,05 của một CPU lõi và điều này không đủ để xử lý số liệu cho một số lượng lớn nhóm như vậy. Chủ yếu sử dụng bộ lập lịch CFS.
Thông thường, việc khắc phục các sự cố như vậy rất đơn giản và chỉ cần phân bổ thêm tài nguyên cho nhóm. Tuy nhiên, trong GKE, tùy chọn này không khả dụng trong giao diện người dùng hoặc thông qua gcloud CLI. Điều này là do Google bảo vệ tài nguyên hệ thống khỏi bị sửa đổi, điều này có thể hiểu được vì tất cả việc quản lý đều do họ thực hiện.
Chúng tôi phát hiện ra rằng chúng tôi không phải là những người duy nhất gặp phải sự cố này và đã phát hiện ra sự cố tương tự khi tác giả cố gắng thay đổi định nghĩa nhóm theo cách thủ công. Anh ấy đã thành công, nhưng chúng tôi thì không. Khi chúng tôi cố gắng thay đổi giới hạn tài nguyên trong tệp YAML, GKE đã nhanh chóng khôi phục chúng.
Chúng tôi cần phải tìm một giải pháp khác.
Bước đầu tiên của chúng tôi là hiểu lý do tại sao các giới hạn tài nguyên được đặt thành các giá trị này. Nhóm này bao gồm hai vùng chứa: metrics-server
và addon-resizer
. Cái sau chịu trách nhiệm điều chỉnh các tài nguyên khi các nút được thêm hoặc xóa khỏi cụm, hoạt động giống như một người chăm sóc cho tính năng tự động chia tỷ lệ dọc của cụm.
Định nghĩa dòng lệnh của nó như sau:
command: - /pod_nanny - --config-dir=/etc/config - --cpu=40m - --extra-cpu=0.5m - --memory=35Mi - --extra-memory=4Mi ...
Trong định nghĩa này, CPU và bộ nhớ đại diện cho tài nguyên cơ sở, trong khi extra-cpu
và extra-memory
đại diện cho tài nguyên bổ sung trên mỗi nút. Các tính toán cho 180 nút sẽ như sau:
0.5m * 180 + 40m=~130m
Logic tương tự được áp dụng cho tài nguyên bộ nhớ.
Thật không may, cách duy nhất để tăng tài nguyên là thêm nhiều nút hơn, điều mà chúng tôi không muốn làm. Vì vậy, chúng tôi quyết định khám phá các lựa chọn khác.
Mặc dù không thể giải quyết vấn đề hoàn toàn, chúng tôi muốn ổn định việc triển khai càng nhanh càng tốt . Chúng tôi đã biết rằng một số thuộc tính trong định nghĩa YAML có thể được thay đổi mà không bị GKE khôi phục. Để giải quyết vấn đề này, chúng tôi đã tăng số lượng bản sao từ 1 lên 5 , thêm kiểm tra tình trạng và điều chỉnh chiến lược triển khai theo bài viết này .
Những hành động này đã giúp giảm tải cho phiên bản máy chủ chỉ số và đảm bảo rằng chúng tôi luôn có ít nhất một nhóm hoạt động có thể cung cấp chỉ số. Chúng tôi đã dành một chút thời gian để xem xét lại vấn đề và làm mới suy nghĩ của mình. Giải pháp cuối cùng trở nên đơn giản và rõ ràng khi nhìn lại.
Chúng tôi đã tìm hiểu sâu hơn về phần bên trong của trình bổ trợ thay đổi kích thước và phát hiện ra rằng nó có thể được định cấu hình thông qua tệp cấu hình và các tham số dòng lệnh. Thoạt nhìn, có vẻ như các tham số dòng lệnh sẽ ghi đè lên các giá trị cấu hình, nhưng thực tế không phải vậy.
Khi điều tra, chúng tôi thấy rằng tệp cấu hình được kết nối với nhóm thông qua các tham số dòng lệnh của bộ chứa addon-resizer:
--config-dir=/etc/config
Tệp cấu hình được ánh xạ dưới dạng Bản đồ cấu hình với tên metrics-server-config
trong không gian tên hệ thống và GKE không khôi phục cấu hình này!
Chúng tôi đã thêm tài nguyên thông qua cấu hình này như sau:
apiVersion: v1 data: NannyConfiguration: |- apiVersion: nannyconfig/v1alpha1 kind: NannyConfiguration baseCPU: 100m cpuPerNode: 5m baseMemory: 100Mi memoryPerNode: 5Mi kind: ConfigMap metadata:
Va no đa hoạt động! Đây là một chiến thắng cho chúng tôi.
Chúng tôi đã để lại hai nhóm có kiểm tra tình trạng và chiến lược không có thời gian ngừng hoạt động trong khi cụm đang thay đổi kích thước và chúng tôi không nhận được bất kỳ cảnh báo nào nữa sau khi thực hiện những thay đổi này.