Một vài lời khuyên khi vận hành Kubernetes
Lời nói đầu
Bắt đầu một năm mới mình cũng muốn bản thân bắt đầu lại một số thói quen mà mình cho rằng là tốt đã bị quên mất. Gần đây mình có đọc được 1 bài viết chia sẻ về kinh nghiệm sử dụng Kubernetes thì chợt nhận ra bản thân cũng đã bắt đầu sự nghiệp ngay với Kubernetes mà chưa lập được ra bất cứ một cuốn "runbook" nào để áp dụng sau này. Chính vì vậy trong bài viết này mình sẽ đào bới lại những kỷ niệm đau đớn trong quá khứ để đưa ra cho bạn những bài học mình học đau đớn đã học được trong quá khứ 😢. Okay let's go!
1. Hãy sử dụng Kubernetes trên nền tảng cloud
Mình rất hiểu anh em khi bắt đầu làm việc với Kubernetes rất khoái dựng các cụm K8s bằng tay trên các con máy ảo, đặc biệt là sau cụm K8s đầu tiên thành công thì sẽ muốn dựng thêm rất nhiều các cụm khác nữa. Nhưng tin mình đi, đến khi các bạn gặp các lỗi oái oăm liên quan đến mặt hạ tầng của Kubernetes thì các bạn sẽ phải nghĩ lại đấy.
Kubernetes là một hệ thống nhiều thành phần và phức tạp, một thành phần trong hệ thống đó gặp gián đoán có thể gây ảnh hưởng từ nhỏ đến rất lớn tới các dịch vụ khác. Phần lớn các vấn đề khoai của Kubernetes mà mình gặp thường đến từ các thành phần hạ tầng như: DNS, kube-proxy (Networking), Storage, master nodes,... Khi gặp phải các vấn đề này có thể mất đến vài tuần để xử lý dứt điểm, đồng thời có thể đem lại cả những hệ quả không mong muốn. 80% các vấn đề trước mình gặp với Kubernetes đều có thể "phòng ngừa" được bằng cách đẩy trách nhiệm này qua bên các nhà cung cấp cloud như EKS hay GKE, họ có những chuyên gia để giúp chúng ta việc đó.
Tự xây dựng và quản lý một cụm Kubernetes từ đầu cũng rất sướng khi có thể tùy chỉnh đủ thứ, cài đặt các cộng cụ yêu cầu truy cập sâu nhưng đánh đổi lại sẽ là những công việc vận hành hóc búa và nhàm chán có thể không tạo ra giá trị gì như: nâng cấp version cluster, thêm/bớt worker node,...
2. Xem xét ứng dụng trước khi triển khai lên Kubernetes
Đây xem chừng là một công việc hiển nhiên khi xây dựng kiến trúc cho bất cứ một ứng dụng nào, nhưng vì nó rất quan trọng mà trước đây có đôi lần mình cũng bỏ qua nên cũng muốn nhắc lại để khắc cốt ghi tâm 🙏. Hãy đánh giá ứng dụng của bạn trên một vài tiêu chí sau:
- Đánh giá kiến trúc ứng dụng: Ứng dụng của bạn là stateful hay stateless, có cần các thành phần gì đặc biệt mà không chạy trên container được hay không,..
- Lượng tài nguyên yêu cầu: Một ứng dụng mới chỉ boot lên đã tốn 3-4 GB memory có lẽ sẽ không phù hợp với nền tảng chuyên dùng cho microservice như K8s
- Hiệu Năng và Độ Ổn Định: Ứng dụng bạn cần hiệu năng và độ ổn định đến mức nào? một ứng dụng yêu cầu đọc ghi với mức IOPS cao như Database có lẽ sẽ thích hợp hơn với máy chủ vật lý hoặc máy ảo (VM) để cung cấp mức IOPS cao nhất.
- Chi phí vận hành: Về mặt con người, khi chạy ứng dụng trên Kubernetes bạn sẽ cần có ít nhất một ông Devops trông nom hệ thống tối ngày. Về mặt hạ tầng, chạy 1 ứng dụng để đáp ứng N requests/s có thể chỉ cần 1 con máy ảo 4 CPU/8GB Memory nhưng sẽ cần 3 Node worker 2 CPU / 4 GB Memory để chạy trên Kubernetes.!
Để hiểu rõ hơn ta đến với ý tiếp theo.
3. Không phải ứng dụng nào cũng phù hợp với Kubernetes
Trong thời gian đầu làm quen với Kubernetes thường chúng ta hay mắc lỗi đưa toàn bộ tất cả các ứng dụng lên nền tảng này mà quên mất rằng: Môi trường Kubernetes có tính biến động lớn. Workload nhỏ nhất trong K8s là Pod, thành phần này rất dễ có thể bị xóa đi và thay bằng một pod khác vì những yếu tố rất rất nhỏ.
Chắc bạn sẽ không muốn chạy database MySQL của mình chỉ có một node master (Mô hình Master-Slave) mà node Master chịu trách nhiệm Write thi thoảng bị xóa đi tạo lại đâu nhỉ. Ngoài ra khi sử dụng qua tầng ảo hóa yếu tố về ổ đĩa cũng bị ảnh hưởng đôi chút.
Đó là yếu tố về hiệu năng và độ ổn định, lượng tài nguyên tiêu thụ cũng là một yếu tố khác chúng ta cần quan tâm.
Ví dụ với một ứng dụng Redis có lưu trữ 10 triệu key, khi vừa boot lên redis sẽ load toàn bộ 10 triệu key vào database khiên memory sử dụng hết ngay 11GB! ...cho 1 node. Nếu bạn cố đấm ăn xôi thì trong cụm cluster của bạn phải có node có memory ít nhất từ 14GB đổ lên do còn chừa dung lượng cho các dịch vụ hệ thống. Thêm vào đó bạn không chỉ phải duy trì duy nhất 1 node to mà sẽ phải duy trì nhiều node để tăng khả năng HA khi 1 node có vấn đề. Việc có nhiều các node "to" trong cụm là không dễ dàng và tốn chi phí.
Chốt lại:
- Các ứng dụng đòi hỏi tài nguyên lớn => Không nên chạy trên Kubernetes
- Các ứng dụng đòi hỏi độ ổn định cao, hiệu năng khỏe (Databases) => Không nên chạy trên Kubernetes
- Các ứng dụng stateful => Không nên chạy trên Kubernetes
4. Luôn luôn cấu hình tự động mở rộng (HPA)
Nếu bạn không áp dụng HPA cho ứng dụng của bạn khi triển khai trên Kubernetes thì bạn đã bỏ mất một tính năng cốt lõi của K8s là khả năng tự động mở rộng và thu hẹp. Khi viết các file manifest chúng ta rất hay bỏ qua việc viết HPA do nghĩ có thể không cần thiết hoặc dự định viết sau... và không còn sau đó nữa.
Khi cấu hình thông số cho HPA bạn cần biết ứng dụng của mình nên scale theo metrics nào. Thông thường chúng ta sẽ scale theo CPU nhưng có khi ứng dụng sẽ cần scale theo số lượng request/s, số lượng message được gửi vào queue,... Để tìm được các thông số min pod, max pod hay trigger threshold hợp lý thì bạn cần có thử nghiệm và chạy thực tế.
Để tìm hiểu thêm về công cụ KEDA cho phép bạn scale theo nhiều metrics ngoài các metric của Kubernetes các bạn có thể đọc thêm bài này HPA là gì? Auto scaling pod bằng HPA và KEDA
Bài học lớn: Trước đây mình cũng hay mắc lỗi nghĩ rằng ứng dụng sẽ chẳng bao giờ có traffic đột biến quá lớn đâu nên khi cấu hình số lượng max pod thường sẽ chỉ cấu hình cùng lắm gấp 2 so với bình thường. Nhưng vào 1 ngày đẹp trời lượng traffic từ đâu ùa đến tăng gấp 10 và số lượng pod chỉ tăng gấp đôi đã không để đáp ứng được lượng request lớn gây crash pod liên tục. Bài học ở đây là nếu bạn sử dụng các nền tảng cloud với lượng resource "unlimit" bạn nên cân nhắc cấu hình số worker node và max pod ở 1 ngưỡng lớn để có thể đáp ứng được các lượng request bất ngờ. Việc này sẽ giúp hệ thống của bạn có thể tự lo liệu với các lượng traffic lớn hoặc giúp bạn kéo dài thêm 1 khoảng thời gian trước khi xử lý bằng tay.
5. Sử dụng các công cụ vừa đủ
Kubernetes nổi lên nhưng một hiện tượng vài năm gần đây kéo theo đó là 1 loạt các công cụ được sinh ra để tự động hóa, tối ưu công việc khi làm với Kubernetes. Tuy nhiên, cái gì nhiều quá cũng không tốt. Nhiều công cụ gây ra tốn tài nguyên, mất thời để cả team có thể làm chủ công cụ,... Hại thì nói không hết nổi, chúng ta chỉ nên tập trung vào những công cụ tối ưu nhất, được cộng đồng tin tưởng và chỉ nên dùng tối đa 1 công cụ trong từng mảng cần thiết. Dưới đây là một số công cụ mình đang dùng:
- Ingress: Nginx, Istio (nâng cao)
- Network: Cilium, KubeShark (debug only)
- Monitor: Grafana, Prometheus
- CLI: OpenLens, kubectl + kubecolor
6. Cân nhắc khi sử dụng Operator
Operator là một thành phần được cài đặt để mở rộng chức năng cho Kubernetes. Thường thấy là các Operator giúp khởi tạo các cụm ứng dụng có mô hình phức tạp như MariaDB, Redis Cluster, Kafka components,...
Đọc thêm về Operator tại đây
Các operator là phần mở rộng thêm được cộng đồng hoặc một tổ chức đóng góp phát triển thường có cấu trúc "khá phức tạp". Các nguy cơ khi sử dụng operator có thể là:
- Operator không được update thường xuyên có thể chứa nhiều bug
- Operator có độ phản hồi chậm trong 1 số trường hợp
- Ứng dụng được tạo bởi operator upgrade khá khó khăn (có thể sẽ phải upgrade operator trước khi muốn upgrade ứng dụng)
- ...
7. Đừng quên cấu hình resource request và limit
Chắc các bạn cũng có thể mờ mờ hình dung được hệ quả của việc không cấu hình CPU, memory request và limit cho ứng dụng. Về cơ bản khi không cấu hình request resource, ứng dụng sẽ nhảy vào bất cứ node nào dùng node đó đã hết tài nguyên để đáp ứng. Không cấu hình limit resource khiến ứng dụng có thể tham lam chiếm hết tài nguyên của node gây quá tải.
Hệ quả nhẹ nhàng:
- Ứng dụng sẽ có hiệu năng nghèo nàn, hay timeout (throttling)
- Ứng dụng sẽ bị gián đoạn/không ổn định do node force xóa pod (đôi khi bạn sẽ thấy pod có trạng thái Evicted)
Nặng hơn:
- Node sẽ bị down hoàn toàn
- Ứng dụng không thể khởi động lại do bị tắt đột ngột.
Việc tìm được thông số cấu hình cho resource request và limit cũng là một bài toán tốn nhiều giấy mực 🤣. Nếu bạn tò mò về chủ đề này thì hãy cho mình biết, mình sẽ viết 1 bài để chia sẻ các tìm resource request và limit cho hợp lý.
Kết
Hy vọng các ý tưởng và bài học trên sẽ giúp bạn đưa ra các quyết định một lúc nào đó trong công việc. Have a nice day~! 👏👏👏
Nếu thấy bài viết hay vậy nhờ bạn Upvote và chia sẻ cho người bạn thấy hữu ích để mình có thêm tý fame nhé. Thank anh em.
Chuyên mục quảng cáo
Nếu như bạn đang gặp khúc mắc trong vấn đề chuyên môn hay cần người hỗ trợ về mặt hệ thống, DevOps tools thì mình tự tin có thể hỗ trợ được bạn. Liên hệ với mình để trao đổi thêm nhé https://hoangviet.io.vn/
All rights reserved