Hành trình "thuần phục" ông quản gia Jenkins: Từ những đêm thức trắng đến hệ thống CI/CD mượt mà
Chào anh em trên Viblo!
Nếu anh em làm backend đủ lâu, chắc hẳn ai cũng từng trải qua cái thời kỳ "nguyên thủy" của việc deploy code. Nhớ lại hồi đó, mỗi lần release tính năng mới cho cái API viết bằng Node.js hay đẩy bản cập nhật cho con app Laravel, quy trình của mình trông như thế này: SSH vào server -> git pull -> chạy npm install hoặc composer install -> chạy migration -> restart service.
Mọi thứ có vẻ ổn cho đến khi team đông lên, số lượng microservices tăng chóng mặt (nhất là khi mình bắt đầu chẻ nhỏ hệ thống và viết thêm vài service bằng Golang). Việc deploy bằng tay trở thành một cơn ác mộng. Rủi ro gõ nhầm lệnh, quên bước, hoặc tệ nhất là sập production lúc nửa đêm.
Và đó là lúc mình tìm đến Jenkins – "ông quản gia" khét tiếng trong làng CI/CD. Hôm nay, mình muốn chia sẻ lại những kinh nghiệm xương máu, những cú vấp ngã và cả những bài học mình rút ra được sau một thời gian dài ăn ngủ cùng công cụ này.
1. Tuần trăng mật và Cú lừa mang tên "Cấu hình trên giao diện" (Freestyle Project)
Lần đầu cài đặt Jenkins, cảm giác thật sự rất "phê". Giao diện tuy hơi cổ điển nhưng việc click chuột tạo một job, điền vài dòng shell script và nhìn cái chấm xanh (Success) hiện lên mang lại một cảm giác thành tựu to lớn.
Nhưng "tuần trăng mật" kết thúc rất nhanh.
Khi số lượng project tăng lên, việc cấu hình qua giao diện (Freestyle project) bộc lộ điểm yếu chí mạng. Bạn không thể track được lịch sử thay đổi cấu hình (ai đã sửa lệnh build?), khó tái sử dụng, và nếu con server Jenkins "tạch", bạn mất trắng toàn bộ công sức setup.
Kinh nghiệm rút ra: Hãy quên Freestyle Project đi và đến ngay với Jenkinsfile (Pipeline as Code).
Việc định nghĩa toàn bộ quy trình CI/CD (Build, Test, Deploy) trong một file Jenkinsfile đặt cùng source code giúp bạn quản lý nó như bất kỳ file code nào khác. Code thay đổi, pipeline thay đổi theo. Mọi thứ minh bạch và có thể review được.
2. Cạm bẫy "Plugin Hell" (Địa ngục Plugin)
Một trong những sức mạnh lớn nhất của Jenkins là hệ sinh thái plugin khổng lồ. Bạn cần gì cũng có plugin hỗ trợ: tích hợp Slack, Telegram, Docker, Kubernetes, AWS...
Hồi mới dùng, mình mắc một sai lầm y hệt người mới đi siêu thị: cái gì cũng muốn bỏ vào giỏ. Mình cài vô tội vạ các loại plugin. Hậu quả là gì?
- Con Jenkins trở nên ì ạch, ngốn RAM khủng khiếp.
- Xung đột phiên bản giữa các plugin.
- Tệ nhất là khi update Jenkins core, một loạt plugin lăn ra chết, kéo theo toàn bộ hệ thống CI/CD tê liệt.
Kinh nghiệm rút ra:
- Less is more. Chỉ cài những plugin thực sự cần thiết.
- Ưu tiên dùng script bash/shell trực tiếp trong Jenkinsfile thay vì phụ thuộc vào một plugin bên thứ ba nếu việc đó đơn giản (ví dụ: cURL lên một webhook thay vì cài nguyên cái plugin chỉ để gửi notification).
3. Bài toán tài nguyên (OOM Killed - Nỗi ám ảnh kinh hoàng)
Bạn đã bao giờ thấy job Jenkins đang chạy ngon lành thì đột ngột đỏ lòm, log báo lỗi Killed hoặc Out of Memory chưa?
Mình đã từng vò đầu bứt tai vì điều này, đặc biệt là khi server Jenkins phải gánh những job nặng như build các binary của Golang hoặc chạy một quả npm install siêu to khổng lồ. Mặc định, Jenkins sẽ chạy các job trực tiếp trên Master node. Nếu bạn có 5-10 job chạy cùng lúc, server sẽ sập.
Kinh nghiệm rút ra:
- Tuyệt đối không chạy job nặng trên Master node. Master chỉ nên làm nhiệm vụ điều phối.
- Sử dụng Jenkins Agents (Slave nodes): Cấu hình các máy chủ khác (hoặc container) làm agent để gánh việc.
Tích hợp Docker làm Agent: Đây là chân ái! Thay vì phải cài sẵn Node, PHP, Go, Java lên server Jenkins, mình cấu hình để mỗi bước trong pipeline chạy trong một Docker container tách biệt. Code Laravel sẽ được test trong container PHP, code Go được build trong container Golang. Build xong, container tự hủy, trả lại môi trường sạch sẽ.
4. Dọn dẹp Workspace – Đừng để "rác" ngập nhà
Khi Jenkins clone code về và build, nó sẽ tạo ra một thư mục workspace. Nếu bạn không dọn dẹp, qua hàng trăm lần build, ổ cứng server sẽ bị ăn mòn cho đến lúc full disk 100%. Lúc đó thì không ssh vào server được chứ đừng nói là build.
Kinh nghiệm rút ra: Luôn nhớ thêm step cleanWs() (Clean Workspace) vào cuối mỗi pipeline trong khối post { always { ... } }. Chuyện nhỏ nhưng cứu bạn khỏi những đêm thức dậy mở rộng dung lượng ổ cứng đấy.
Lời kết
Jenkins không phải là công cụ hào nhoáng nhất, hiện đại nhất (chúng ta có GitHub Actions, GitLab CI rất xịn xò), giao diện của nó đôi khi bị chê là "cổ lỗ sĩ". Nhưng sự ổn định, khả năng tùy biến vô hạn và sự tự do mà nó mang lại là thứ khó có công cụ nào thay thế được trong các hệ thống doanh nghiệp phức tạp.
Quá trình làm việc với Jenkins đã dạy cho mình tư duy về tự động hóa, về cách kiến trúc một quy trình deploy an toàn và cách quản lý tài nguyên hệ thống. Hy vọng những chia sẻ này sẽ giúp anh em bớt đi vài "cú vấp" trên con đường xây dựng hệ thống CI/CD cho riêng mình.
Anh em đang dùng công cụ CI/CD nào? Có kỷ niệm đau thương nào với Jenkins không? Hãy chia sẻ ở phần bình luận nhé! Happy coding!
All rights reserved