Chào anh em, hôm nay mình sẽ chia sẻ cho anh em về trải nghiệm thực tế của mình với Jenkins, một công cụ đã thay đổi hoàn toàn cách mình làm việc. Đây là câu chuyện từ chính trải nghiệm của mình, hy vọng sẽ mang lại cho các anh em những góc nhìn thú vị.

Tại sao lại chọn Jenkins?

Hiện nay có rất nhiều công cụ ưu việt, hỗ trợ cho việc triển khai CICD, có thể kể đến như Gitlab CI, Circle CI, Travis CI và nhiều công cụ khác nữa. Tuy nhiên theo mình thấy, Jenkins vẫn luôn là một lựa chọn phổ biến và được ưa chuộng. Vậy điều gì làm cho Jenkins trở nên đặc biệt?

Opensource và cộng đồng hỗ trợ lớn: Chúng ta có thể dễ dàng setup Jenkins ở local phục vụ cho việt testing, hoặc có thể setup jenkins ở trên cả những dự án lớn hoàn toàn miễn phí một cách dễ dàng. Bên cạnh đó, với một cộng đồng hỗ trợ rất lớn nên khi mình gặp bất kỳ lỗi gì trong quá trình vận hành và sử dụng thì hầu như đều có thể tìm kiếm ở các diễn đàn.
Khả năng mở rộng mạnh mẽ: Một ưu điểm tiếp theo có thể kể đến là Jenkins có hàng ngàn plugin giúp mở rộng chức năng của nó. Bên cạnh đó chúng ta hoàn toàn có thể tích hợp Jenkins với nhiều công cụ khác của DevOps như Git, Docker, K8S và nhiều cái khác nữa. Ở những dự án phức tạp thì điều này là hoàn toàn cần thiết.

Bước đầu làm quen với Jenkins

Ban đầu, việc cài đặt Jenkins cũng không quá phức tạp. Chỉ cần tải về, cài đặt và cấu hình một chút là xong. Giao diện của Jenkins khá thân thiện, và có rất nhiều plugin hỗ trợ. Mình bắt đầu tạo các job đầu tiên để tự động hóa việc build và kiểm tra mã nguồn.
Dưới đây là một ví dụ đơn giản về việc tạo 1 pipeline với groovy script, hỗ trợ cho việc build, test và deploy. Tuy nhiên trong các dự án thực tế, Jenkins pipeline sẽ phức tạp hơn nhiều. Mình sẽ chia sẻ nó ở những phần tiếp theo.

Pipeline Sample
Pipeline Sample

Những kinh nghiệm và các kỹ thuật khi sử dụng Jenkins

Luôn backup Jenkins

Trong dự án thực tế thì jenkins sẽ được sử dụng bởi rất nhiều người, bao gồm cả team Dev, team QC chứ không riêng gì chỉ DevOps, sẽ có rất nhiều job quan trọng mà người ta đã cấu hình sẵn ở trong đó, ngoài ra còn những artifact, log đã được build hay là cả những cấu hình của plugin cũng rất quan trọng. Vậy nên, hãy luôn nhớ backup Jenkins định kỳ để tránh những hậu quả không đáng có trong quá trình sử dụng Jenkins. Một plugin mà mình recommend anh em sử dụng để hỗ trợ cho việc backup Jenkins là Thin Backup.
Plugin này cũng khá dễ sử dụng, mình có thể dễ dàng cấu hình backup directory và chỉ định chi tiết thời gian backup trong ngày. Anh em có thể restore dễ dàng khi cần thiết.
Thin Backup

Jenkins Slave

Một trong những kỹ thuật quan trọng mà mình đã áp dụng là sử dụng Jenkins Slave. Trong các dự án, việc build và kiểm tra mã nguồn trên một máy chủ duy nhất không đủ đáp ứng nhu cầu. Hiện nay nếu như Jenkins được deploy trên K8S cluster thì hầu như các job sẽ được build bằng tài nguyên của một con agent. Cụ thể là một con pod trên K8S. Tại sao lại như vậy? Kubernetes cho phép tự động mở rộng (scaling) các Pod dựa trên nhu cầu thực tế. Khi có nhiều job cần chạy, Kubernetes sẽ tự động tạo thêm các Pod để xử lý, và khi không cần thiết nữa, các Pod sẽ được hủy bỏ. Điều này giúp tối ưu hóa việc sử dụng tài nguyên và giảm chi phí.

pipeline {
  agent {
    kubernetes {
      yaml """
        apiVersion: v1
        kind: Pod
        spec:
          containers:
          - name: jnlp
            image:docker.io/jenkins/inbound-agent:jdk17
      """
    }
  }

Nếu không sử dụng K8S thì việc cấu hình Jenkins Slave cũng khá đơn giản. Đầu tiên, mình tạo một node mới trong Jenkins và chọn loại “Permanent Agent”. Sau đó, mình cấu hình các thông số như tên node, số lượng executor, và phương thức kết nối (thường là qua SSH). Khi đã cấu hình xong, mình có thể chỉ định các job cụ thể chạy trên các slave node này, giúp tối ưu hóa tài nguyên và tăng tốc độ build.

Jenkins Shared Library

Một kỹ thuật khác mà mình thấy rất hữu ích là Jenkins Shared Library. Đây là cách để chia sẻ các đoạn mã pipeline giữa các dự án khác nhau, giúp giảm thiểu việc lặp lại mã và giữ cho code luôn “DRY” (Don’t Repeat Yourself).

Để tạo một Shared Library, mình cần tạo một repository chứa các script Groovy và cấu trúc thư mục theo chuẩn của Jenkins. Sau đó, mình cấu hình Jenkins để sử dụng thư viện này bằng cách thêm nó vào phần “Global Pipeline Libraries” trong cấu hình hệ thống. Khi đã cấu hình xong, mình có thể sử dụng các hàm và biến toàn cục từ thư viện này trong các pipeline của mình bằng cách sử dụng annotation @Library.

@Library('my-shared-library') _
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                script {
                    mySharedLibrary.build()
                }
            }
        }
        stage('Test') {
            steps {
                script {
                    mySharedLibrary.test()
                }
            }
        }
        stage('Deploy') {
            steps {
                script {
                    mySharedLibrary.deploy()
                }
            }
        }
    }
}

Configuration as Code

Cuối cùng, một kỹ thuật không thể thiếu là Jenkins Configuration as Code (JCasC). Đây là cách để định nghĩa toàn bộ cấu hình của Jenkins bằng file YAML, giúp việc quản lý cấu hình trở nên dễ dàng và có thể kiểm soát phiên bản.

Để sử dụng JCasC, mình cài đặt plugin “Configuration as Code” và tạo một file YAML chứa các thông số cấu hình của Jenkins. File này có thể được lưu trữ trong hệ thống quản lý mã nguồn (SCM) để theo dõi các thay đổi và dễ dàng khôi phục lại cấu hình cũ khi cần thiết. Khi cần áp dụng cấu hình mới, mình chỉ cần tải lại file YAML này và Jenkins sẽ tự động cập nhật cấu hình.

jenkins:
  systemMessage: "Welcome to Jenkins configured as code!"
  numExecutors: 5
  scmCheckoutRetryCount: 2
  securityRealm:
    local:
      allowsSignup: false
      users:
        - id: "admin"
          password: "admin"
  authorizationStrategy:
    loggedInUsersCanDoAnything:
      allowAnonymousRead: false
  tools:
    jdk:
      installations:
        - name: "Java 11"
          home: "/usr/local/java-11"
  nodes:
    - permanent:
        name: "slave-node"
        remoteFS: "/home/jenkins"
        launcher:
          ssh:
            host: "slave-host"
            credentialsId: "ssh-credentials"

Kết Luận

Vậy là bài viết về Jenkins của mình đến đây là hết. Hy vọng rằng qua bài viết này, anh em sẽ hiểu rõ hơn về Jenkins và cách nó có thể giúp ích trong công việc của mình. Nếu có bất kỳ câu hỏi hay thắc mắc nào, đừng ngần ngại chia sẻ nhé!

Hẹn gặp lại trong những bài viết tiếp theo!