Tác giả: Minh HiếuThông tin liên hệ:devopsedu.vn: mhieu96facebook: Minh Hiếu BùiChào anh em mình là Hiếu. Gần đây mới nảy ra ý tưởng khi theo dõi anh Mạnh lâu là mình sẽ làm các usecase, issue thực tế mà mình gặp phải và cách khắc phục lên devopsedu.vn và đăng tương ứng đăng bài lên group DevOps VietNam để hỏi ý kiến anh em rồi học hỏi thêm các cách fix tối ưu hơn nữa và cập nhật lại bài viết vừa có một nơi lưu trữ tập trung vừa có thể giúp được anh em vì không phải ai cũng có thể trải qua hết các usecase giúp người, giúp ta cả nhà đều vui 😀Và usecase đầu tiên mình chia sẻ cũng là usecase đầu tiên mình gặp phải khi bắt đầu care sâu hơn hệ thống cách đây cũng khá lâu lúc ý chắc junior+ middle- 😅Hệ thống CI/CD bị chậm khi chạy pipeline trong môi trường KubernetesBài toánMình gặp vấn đề này trên hệ thống CI/CD được thiết lập trên Jenkins và chạy các pipeline trong một cụm Kubernetes. Khi team phát triển tăng số lượng build lên, pipeline CI/CD bắt đầu chậm lại, kéo dài từ 10 phút lên tới 40 phút hoặc hơn.Biểu hiệnBiểu hiện này là mình thấy ngay và nghiên cứu theo dõi ra được.Build job bị pending lâu trên JenkinsPod của job không được tạo kịp hoặc bị stuck ở trạng thái ContainerCreatingKhi job chạy việc download dependency (Maven, NPM) bị chậm bất thường.Nguyên nhânNguyên nhân thì đến từ kinh nghiệm cá nhân thôi (nếu các bác gặp tương tự có thể trao đổi với em nha)Hạn chế tài nguyên: Cluster Kubernetes không đủ tài nguyên để xử lý số lượng build tăng đột biến. Node thiếu CPU và RAM, dẫn đến scheduling bị trì hoãn.DNS Slowness: CoreDNS trong cluster bị nghẽn vì quá nhiều request từ các pod, đặc biệt khi mỗi job tải về các dependency từ internet.Shared storage bottleneck: Các job lưu trữ build artifact trên một Persistent Volume (PV) được mount từ một NFS, gây ra IOPS contention khi nhiều job truy cập cùng lúc.Biện phápCác giải pháp fix cũng là kinh nghiệm cá nhân nha (update: mình đã thêm các giải pháp dựa trên ý kiến đóng góp của anh em trên group DevOps VietNam ở bài viết: tại đây nha)Tăng cường tài nguyên cho cluster: thêm các node vào cluster, thiết lập limit và request tài nguyên chuẩn cho từng job để tránh lãng phí tài nguyên trên clusterTối ưu hóa CoreDNS: Tăng số lượng replica của CoreDNS từ 2 lên 5, sử dụng cache để giảm tải cho CoreDNS bằng cách thêm plugin cache trong config, chuyển đổi một số job để sử dụng IP trực tiếp cho các dependency nội bộ thay vì rely vào DNS.Giảm tải shared storage: Chuyển từ NFS sang S3-compatible storage (dùng MinIO) để tăng tốc độ lưu trữ artifact và loại bỏ tình trạng contention IOPS, Đối với job chỉ cần artifact tạm thời, dùng EmptyDir (disk ephemeral) để tăng tốc.Tối ưu hóa caching trong pipeline: Thêm caching trên từng stage của pipeline (Maven/NPM cache được lưu trữ trên workspace riêng của Jenkins hoặc trong S3).Giải pháp của anh em góp ý:Bác Nguyễn Tuấn Hưng: "Bên mình cũng đang có usecase tượng tự của bạn. Bên mình thì gặp 2 vấn đề chính sau:1 - Pod của job jenkins do có sử dụng một số image custom nên image nặng và thời gian khởi tạo pod lâu.2 - Thời gian build image (bao gồm download và install dependency) rất lâu, thường từ 10-15p cho một image nodejs.Hướng xử lý thì mình thấy xử lý được 2 vấn đề này thì cũng đã giảm thiểu được kha khá thời gian build của job rồi.1 - Để tối ưu cho việc khởi tạo pod, bên mình sử dụng private registry để kết nối từ cụm k8s tới image registry pull image cho pod về nhanh hơn. Tối ưu lại image size.2 - Tối ưu thời gian build ứng dụng, vấn đề này thì bên mình đang:- Sử dụng Nexus repository để làm private repo lưu trữ dependencies, giảm thiểu việc phải download dependencies từ internet.- Do build thành image, bên mình tối ưu lại Dockerfile, có thể multi-staged hoặc giảm bớt các layer không cần thiết (tuy nhiên sẽ phải đánh đổi giữa image size final và thời gian build)- Do cicd là việc lặp lại liên tục, gần như các dependencies cũng không có sự thay đổi quá nhiều, mình có build image base cho từng project, trong image này đã có sẵn dependencies được cài từ trước, trong bước build mình vẫn "npm i" để cài đặt lại dependencies. Khi này dependencies đã có sẽ không cần cài lại nữa.Cuối cùng thì vấn là vấn đề tài nguyên có hạn, bạn có thể cân nhắc cấu hình số lượng concurrent builds để giảm tải cho cụm k8s. Nhiều job cùng lúc quá thì nhanh nhưng cũng không hẳn là tốt 😀" Bác Liam Nguyen:"Xài Karpenter để add thêm executor node cho nhanh. Cập nhật các builtin components/ plugin lên version mới nhất đồng bộ theo cloud provider documents. Network cũng nên thiết lập riêng, shared network với cục cluster chạy test hay product dễ bị cạn IP, bottleneck" Bác Phạm Khang Ninh:"về việc download dependency, tại sao bên bác không build hẳn 1 base image có sẵn các dependency đó? Rồi những thằng khác chỉ việc ref tới base image này để build trong multi stage, nó sẽ tiết kiệm kha khá thời gian build của ~ pipeline dùng maven/npm luôn ấy" Kết quảThời gian chạy pipeline giảm từ 40 phút xuống còn 8-10 phút.Bài học rút ra từ anh emMình đã làm ngay cách tạo base image chứa dependency và chung quy lại là đóng gói nó lại sẵn khỏi cần pull lại trên Internet về. Cảm ơn anh em, mình sẽ làm nhiều hơn các nội dung kiểu này hehe