Triển khai và Cấu hình Jenkins cơ bản trên Kubernetes

Giới thiệu về Jenkins

Jenkins là một nền tảng tự động hóa mã nguồn mở hàng đầu, được sử dụng rộng rãi cho các dự án Tích hợp Liên tục (CI) và Phân phối Liên tục (CD). Nền tảng này cho phép tự động hóa các tác vụ liên quan đến xây dựng, kiểm thử và triển khai phần mềm trên nhiều môi trường khác nhau.

Mục đích của Jenkins

  • Tự động hóa liên tục quá trình xây dựng và kiểm thử các dự án phần mềm.
  • Giám sát quy trình phát triển, nhanh chóng phát hiện và xử lý các vấn đề.
  • Tự động thực hiện các tác vụ định kỳ.

Tại sao nên sử dụng Jenkins?

Việc áp dụng Jenkins mang lại nhiều lợi ích quan trọng trong quy trình phát triển phần mềm:

  • Giảm thiểu công việc thủ công: Tự động hóa toàn bộ quy trình từ lấy mã nguồn, biên dịch, đóng gói, kiểm thử đến triển khai lên máy chủ, loại bỏ các tác vụ lặp đi lặp lại.
  • Phản hồi nhanh chóng: Khi có thay đổi mã nguồn (ví dụ: push lên Git), Jenkins có thể tự động nhận diện, biên dịch, kiểm thử và triển khai đến môi trường mong muốn (dev/test/production).
  • Đảm bảo môi trường nhất quán: Loại bỏ tình trạng "chạy được trên máy tôi nhưng không chạy được trên máy người khác" bằng cách cung cấp một môi trường xây dựng và triển khai chuẩn hóa.
  • Miễn phí và mã nguồn mở: Là một giải pháp được cộng đồng hỗ trợ rộng rãi và được nhiều doanh nghiệp tin dùng.
  • Hỗ trợ đa dạng công nghệ: Tương thích với hầu hết các ngôn ngữ và công cụ phổ biến như Java, Python, Go, Docker, Kubernetes, Git, Maven, Gradle, v.v.

Tóm lại, sử dụng Jenkins giúp giảm bớt công việc thủ công, hạn chế lỗi, tự động hóa quy trình xây dựng và triển khai, đồng thời đảm bảo việc bàn giao dự án ổn định và hiệu quả.

Triển khai Jenkins trên Kubernetes

Phần này sẽ hướng dẫn cách triển khai Jenkins trong môi trường Kubernetes. Chúng ta sẽ sử dụng phương pháp cấp phát động Persistent Volume (PV), nên chỉ cần khai báo Persistent Volume Claim (PVC).

1. Tạo Service Account

Service Account là tài khoản mà Pod của Jenkins sẽ sử dụng để chạy và tương tác với các tài nguyên Kubernetes khác. Chúng ta cần cấp quyền thích hợp cho tài khoản này.

# service-account-jenkins.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-cluster-admin-role # Tên ClusterRole để Jenkins có quyền quản trị
rules:
  - apiGroups: [""] # Quyền truy cập các tài nguyên core API (Pod, Service, ConfigMap, v.v.)
    resources: ["*"] # Truy cập tất cả tài nguyên
    verbs: ["*"] # Thực hiện mọi hành động (get, list, watch, create, update, delete)
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-sa # Tên ServiceAccount cho Jenkins
  namespace: ci-cd # Namespace để triển khai Jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-cluster-admin-binding # Tên ClusterRoleBinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkins-cluster-admin-role # Tham chiếu đến ClusterRole đã tạo
subjects:
- kind: ServiceAccount
  name: jenkins-sa # Tham chiếu đến ServiceAccount đã tạo
  namespace: ci-cd # Trong namespace ci-cd

Đầu tiên, tạo namespace và sau đó áp dụng cấu hình:

kubectl create ns ci-cd
kubectl apply -f service-account-jenkins.yaml

2. Tạo Persistent Volume Claim (PVC)

PVC sẽ yêu cầu một Persistent Volume để lưu trữ dữ liệu của Jenkins, đảm bảo dữ liệu không bị mất khi Pod khởi động lại hoặc di chuyển.

# jenkins-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-data-pvc # Tên PVC
  namespace: ci-cd # Trong namespace ci-cd
spec:
  accessModes:
    - ReadWriteOnce # Chế độ truy cập: chỉ một Pod có thể ghi và đọc
  resources:
    requests:
      storage: 15Gi # Yêu cầu 15GB dung lượng lưu trữ
kubectl apply -f jenkins-pvc.yaml

3. Triển khai Deployment

Deployment sẽ quản lý Pod chạy ứng dụng Jenkins. Chúng ta sẽ gắn PVC đã tạo vào Pod này để lưu trữ dữ liệu tại /var/jenkins_home.

# jenkins-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-master # Tên Deployment
  namespace: ci-cd # Trong namespace ci-cd
  labels:
    app: jenkins-server-app # Label cho Deployment
spec:
  replicas: 1 # Chỉ một bản sao của Jenkins master
  selector:
    matchLabels:
      app: jenkins-server-app # Selector để Pod khớp với Deployment
  strategy:
    type: Recreate # Đảm bảo Pod cũ được dừng trước khi Pod mới khởi động
  template:
    metadata:
      labels:
        app: jenkins-server-app # Label cho Pod
    spec:
      serviceAccountName: jenkins-sa # Sử dụng ServiceAccount đã tạo
      volumes:
        - name: jenkins-storage # Tên volume
          persistentVolumeClaim:
            claimName: jenkins-data-pvc # Gắn với PVC đã tạo
      containers:
      - name: jenkins # Tên container
        image: jenkins/jenkins:lts # Sử dụng phiên bản LTS ổn định của Jenkins
        imagePullPolicy: IfNotPresent # Chỉ kéo ảnh nếu chưa có
        securityContext:
          runAsUser: 0 # Chạy với quyền root bên trong container (để Jenkins có thể tạo các file cần thiết)
        volumeMounts:
          - name: jenkins-storage # Gắn volume
            mountPath: /var/jenkins_home # Đường dẫn lưu trữ dữ liệu Jenkins bên trong container
        ports:
          - name: http-port # Cổng HTTP cho giao diện người dùng
            containerPort: 8080
          - name: agent-port # Cổng JNLP cho kết nối agent
            containerPort: 50000
        resources:
          limits:
            memory: "2Gi" # Giới hạn bộ nhớ 2GB
            cpu: "1" # Giới hạn CPU 1 core
          requests:
            memory: "1Gi" # Yêu cầu bộ nhớ 1GB
            cpu: "0.5" # Yêu cầu CPU 0.5 core
        livenessProbe: # Kiểm tra sức khỏe của Pod
          httpGet:
            path: "/login"
            port: 8080
          initialDelaySeconds: 90
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 6
        readinessProbe: # Kiểm tra khả năng sẵn sàng của Pod để nhận lưu lượng
          httpGet:
            path: "/login"
            port: 8080
          initialDelaySeconds: 90
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
kubectl apply -f jenkins-deployment.yaml

Kiểm tra trạng thái của Pod (quá trình khởi động có thể mất vài phút do các kiểm tra sức khỏe):

kubectl get pod -n ci-cd

4. Mở dịch vụ (Service)

Service sẽ cho phép truy cập vào giao diện web của Jenkins từ bên ngoài Cluster Kubernetes.

# jenkins-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: jenkins-web-svc # Tên Service
  namespace: ci-cd # Trong namespace ci-cd
spec:
  selector:
    app: jenkins-server-app # Selector để Service tìm kiếm Pod của Jenkins
  type: NodePort # Sử dụng NodePort để truy cập từ bên ngoài Cluster
  ports:
    - name: http-web # Cổng cho giao diện web Jenkins
      port: 8080 # Cổng Service
      targetPort: 8080 # Cổng container
      nodePort: 30000 # Cổng NodePort để truy cập từ bên ngoài (ví dụ: 30000)
    - name: jnlp-agent # Cổng cho kết nối Jenkins Agent
      port: 50000 # Cổng Service
      targetPort: 50000 # Cổng container
      nodePort: 31000 # Cổng NodePort cho agent (ví dụ: 31000)
kubectl apply -f jenkins-service.yaml

Kiểm tra thông tin Service:

kubectl get svc -n ci-cd

Bạn có thể truy cập Jenkins qua địa chỉ IP của bất kỳ Node Kubernetes nào trong cluster cùng với NodePort (ví dụ: http://<node-ip>:30000).

Cấu hình Jenkins ban đầu

1. Đăng nhập và lấy mật khẩu quản trị

Sau khi Jenkins khởi động hoàn tất, bạn cần mật khẩu quản trị ban đầu để đăng nhập. Mật khẩu này thường được lưu trong thư mục dữ liệu của Jenkins.

Để lấy mật khẩu, bạn có thể thực hiện như sau (nếu PVC của bạn được ánh xạ ra một thư mục trên host, bạn có thể kiểm tra trực tiếp tại đó):

# Đầu tiên, tìm tên Pod Jenkins
JENKINS_POD=$(kubectl get pod -n ci-cd -l app=jenkins-server-app -o jsonpath='{.items[0].metadata.name}')

# Sau đó, lấy mật khẩu từ bên trong Pod
kubectl exec -ti -n ci-cd $JENKINS_POD -- cat /var/jenkins_home/secrets/initialAdminPassword

Sử dụng mật khẩu hiển thị để đăng nhập vào giao diện web Jenkins.

2. Bỏ qua cài đặt plugin mặc định

Khi đăng nhập lần đầu, Jenkins sẽ hỏi bạn có muốn cài đặt các plugin mặc định hay không. Nên chọn "Select plugins to install" hoặc "Install suggested plugins" và sau đó bỏ chọn tất cả hoặc chọn "None" nếu có tùy chọn. Lý do là các plugin mặc định thường được tải từ máy chủ ở nước ngoài (như Google), có thể gặp vấn đề về kết nối ở một số khu vực.

3. Thiết lập thông tin người dùng

Sau khi bỏ qua hoặc chọn plugin, bạn sẽ được yêu cầu tạo một tài khoản quản trị viên. Hãy cung cấp tên người dùng, mật khẩu và email.

4. Cấu hình ngôn ngữ (tiếng Việt)

Để sử dụng Jenkins với giao diện tiếng Việt, bạn cần cài đặt plugin "Localization: Chinese (Simplified)" (mặc dù tên là tiếng Trung, plugin này bao gồm cả gói ngôn ngữ tiếng Việt). Sau khi cài đặt, bạn có thể thay đổi ngôn ngữ trong phần cài đặt người dùng hoặc cài đặt chung của Jenkins.

5. Thay đổi nguồn cập nhật plugin

Để cải thiện tốc độ tải và cài đặt plugin, bạn nên thay đổi máy chủ cập nhật plugin mặc định của Jenkins sang một mirror trong nước (ví dụ: của Đại học Thanh Hoa hoặc Huawei Cloud). Truy cập Manage Jenkins > Manage Plugins > Advanced.

Thay đổi URL trong phần "Update Site" thành:

  • https://mirrors.tuna.tsinghua.edu.cn/jenkins/update-center.json (Đại học Thanh Hoa)
  • https://mirrors.huaweicloud.com/jenkins/update-center.json (Huawei Cloud)

Sau khi thay đổi trên giao diện web, bạn cũng cần đảm bảo rằng file cấu hình bên trong container Jenkins được cập nhật. Sau khi Jenkins khởi động lại, kiểm tra file /var/jenkins_home/updates/default.json. Nếu cần, bạn có thể chỉnh sửa thủ công:

# Lấy tên Pod Jenkins
JENKINS_POD=$(kubectl get pod -n ci-cd -l app=jenkins-server-app -o jsonpath='{.items[0].metadata.name}')

# Truy cập vào bên trong Pod
kubectl exec -ti -n ci-cd $JENKINS_POD -- /bin/bash

# Bên trong Pod, chỉnh sửa file default.json
sed -i 's/https:\/\/updates.jenkins.io\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' /var/jenkins_home/updates/default.json
sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' /var/jenkins_home/updates/default.json # Thay đổi liên kết kiểm tra kết nối nếu cần
exit

Sau đó, khởi động lại Jenkins để áp dụng thay đổi:

kubectl exec -ti -n ci-cd $JENKINS_POD -- jenkins-cli safe-restart
# hoặc truy cập http://<node-ip>:30000/restart trên trình duyệt

6. Cài đặt các plugin cần thiết

Sau khi cấu hình nguồn cập nhật, bạn có thể truy cập Manage Jenkins > Manage Plugins > Available và tìm kiếm các plugin cần thiết cho dự án của mình. Nên cài đặt tất cả các plugin cần thiết trong một lần và sau đó khởi động lại Jenkins.

Các plugin quan trọng thường dùng:

  • Git: Để kéo mã nguồn từ kho Git.
  • Pipeline: Cho phép định nghĩa quy trình CI/CD dưới dạng mã.
  • Kubernetes: Để tích hợp Jenkins với Kubernetes, cho phép tạo các agent động trên Kubernetes.
  • Localization: Chinese (Simplified): Để có giao diện tiếng Việt.
  • SSH / Publish Over SSH: Để thực hiện các lệnh SSH từ Jenkins đến các máy chủ khác.
  • Maven / Gradle / NodeJS: Tùy thuộc vào loại dự án (Java, Node.js, v.v.).
  • DingTalk / Slack / Email Extension: Các plugin thông báo kết quả xây dựng.
  • Role-based Authorization Strategy: Quản lý quyền hạn chi tiết cho người dùng.
  • Git Parameter: Cho phép chọn nhánh Git động khi chạy job.
  • HTTP Request Plugin: Thực hiện các HTTP request trong pipeline.
  • Pipeline Utility Steps: Cung cấp các bước tiện ích cho pipeline (nén, giải nén, tìm file).

Quản lý Jenkins cơ bản

1. Cấu hình thông báo Email

Để Jenkins có thể gửi thông báo qua email (ví dụ: khi một build thất bại), bạn cần cấu hình SMTP server. Truy cập Manage Jenkins > Configure System > cuộn xuống phần Email Notification.

Điền các thông tin cần thiết:

  • SMTP Server: (Ví dụ: smtp.qq.com cho QQ Mail)
  • Default user e-mail suffix: (@example.com)
  • System Admin e-mail address: (Địa chỉ email của người gửi, ví dụ: user@qq.com)
  • Use SMTP Authentication: (Tick vào và điền Username/Password, Password ở đây là mã ủy quyền (authorization code) của email, không phải mật khẩu đăng nhập thông thường.)
  • Use SSL/TLS: (Tick vào nếu máy chủ SMTP yêu cầu)
  • SMTP Port: (Ví dụ: 465 cho SSL/TLS hoặc 587 cho STARTTLS)

Sau đó, bạn có thể sử dụng nút "Test configuration" để kiểm tra xem cấu hình email đã hoạt động hay chưa.

2. Quản lý Chứng chỉ (Credentials)

Jenkins cần các chứng chỉ để tương tác với các hệ thống bên ngoài như kho mã nguồn (GitLab, GitHub), các máy chủ SSH, hoặc các cluster Kubernetes. Truy cập Manage Jenkins > Manage Credentials > System > Global credentials.

Các loại chứng chỉ phổ biến:

  • Username with password: Để kết nối với kho Git (đối với GitLab phiên bản mới, nên sử dụng Personal Access Token thay vì mật khẩu người dùng), hoặc SSH tới máy chủ.
  • SSH Username with private key: Để kết nối SSH với các máy chủ mà không cần mật khẩu.
  • Secret text: Lưu trữ các token, API key.
  • Kubernetes Service Account: Khi tích hợp với Kubernetes để tạo agent động.

Ví dụ, để kết nối với GitLab, bạn có thể tạo chứng chỉ "Username with password" với username là tên người dùng GitLab và password là Personal Access Token đã tạo trên GitLab.

3. Kiểm tra công việc (Job) đơn giản

Tạo một công việc "Freestyle project" đơn giản để kiểm tra kết nối với Git và thực thi lệnh.

  1. Trên trang chủ Jenkins, chọn New Item > Freestyle project, đặt tên cho job và nhấn OK.
  2. Trong phần Source Code Management, chọn Git.
  3. Nhập Repository URL (ví dụ: https://gitlab.com/your-repo/your-project.git).
  4. Chọn chứng chỉ GitLab bạn đã tạo (nếu kho riêng tư).
  5. Trong phần Build Steps, chọn Execute shell và nhập một lệnh đơn giản, ví dụ: ls -l hoặc echo "Hello from Jenkins!".
  6. Lưu cấu hình và sau đó nhấn Build Now.

Kiểm tra output trong Console Output của job. Nếu thành công, bạn sẽ thấy kết quả của lệnh shell.

Lưu ý: Các job "Freestyle" này thường chạy trên chính Jenkins Master (trong Pod Jenkins bạn đã triển khai). Dữ liệu của job sẽ được lưu trữ trong thư mục làm việc của Jenkins (ví dụ: /var/jenkins_home/jobs/<tên_job>/workspace, thư mục này được lưu trữ trên PVC).

Các vấn đề thường gặp

Một số vấn đề phổ biến khi triển khai Jenkins trên Kubernetes bao gồm các sự cố về mạng (ví dụ: Calico, Flannel), không truy cập được Jenkins từ Node IP, hoặc các vấn đề về quyền hạn khi Jenkins tương tác với các tài nguyên Kubernetes.

Thẻ: Jenkins Kubernetes CI/CD DevOps git

Đăng vào ngày 31 tháng 7 lúc 09:25