0

Hướng dẫn Setup Jenkins cho hệ thống Monolith + Bài học 34 + Quản lý cấu hình Jenkins bằng mã nguồn với Jenkins Configuration as Code (JCasC)

Ở Bài 33, chúng ta đã thiết lập quy trình sao lưu các tệp .xml trong thư mục /var/jenkins_home để phòng chống thảm họa. Tuy nhiên, việc quản trị Jenkins theo kiểu truyền thống — tức là mở trình duyệt web, bấm vào Manage Jenkins -> System, điền tay từng ô địa chỉ SonarQube, bấm tích từng ô phân quyền RBAC (Bài 28), hay khai báo từng máy chủ Agent (Bài 31) — mang lại một vấn đề lớn được gọi là "ClickOps":

  • Không ai biết tuần trước ai đã âm thầm vào giao diện web sửa đổi một thông số hệ thống khiến Pipeline chạy chậm đi.

  • Các tệp .xml sinh ra bởi Jenkins cực kỳ rối rắm, không thể đưa lên Git để đọc hiểu hay thực hiện Code Review như mã nguồn bình thường.

Bài học hôm nay sẽ đưa bạn bước vào kỷ nguyên Infrastructure as Code (IaC) ngay trên Jenkins với công cụ Jenkins Configuration as Code (JCasC): Biến toàn bộ cấu hình của máy chủ Jenkins thành một tệp jenkins.yaml duy nhất, sạch sẽ, có thể quản lý phiên bản trên Git và dựng mới hoàn toàn tự động trong vài giây!

1. Tại sao JCasC là mảnh ghép tối thượng cho hạ tầng CI/CD của hệ thống Monolith?

Hãy so sánh sự khác biệt giữa cách quản trị thủ công qua giao diện (UI ClickOps) và quản trị bằng mã nguồn (jenkins.yaml với JCasC):

Tiêu chí Cấu hình thủ công qua Web UI (ClickOps) Cấu hình bằng mã với JCasC (jenkins.yaml)
Truy vết thay đổi (Audit & Git History) Không biết ai sửa cấu hình gì lúc nào nếu không lục lọi log hệ thống. Mọi thay đổi (thêm Agent, đổi quyền RBAC, thêm Credentials) đều phải tạo Pull Request trên Git, có lịch sử git blame rõ ràng.
Thời gian dựng mới Jenkins Master Mất 2 – 4 giờ ngồi click chuột cài đặt lại từng mục System, Security, Tools, Nodes. 0 giây click chuột: Container Jenkins vừa bật lên sẽ tự động đọc file jenkins.yaml và tự cấu hình xong 100% trước khi bạn kịp mở trình duyệt!
Tính nhất quán (Reproducibility) Rất dễ cấu hình thiếu hoặc lệch thông số khi dựng môi trường Jenkins thử nghiệm. Đảm bảo tạo ra hàng chục máy chủ Jenkins giống hệt nhau đến từng dấu chấm phẩy.
Khả năng khôi phục khi cấu hình sai Nếu lỡ tay sửa sai làm lỗi hệ thống, phải mò mẫm chỉnh lại từng ô trên UI hoặc bung file nén backup .tar.gz. Chỉ cần gõ git revert trên file jenkins.yaml và bấm nút Reload!

2. Cài đặt và khám phá công cụ "Xuất cấu hình hiện tại" của JCasC Plugin

Tin vui là bạn không cần phải ngồi học thuộc lòng cú pháp YAML từ con số 0! Nếu máy chủ Jenkins của bạn đã được cấu hình sẵn từ Bài 1 đến Bài 33, plugin JCasC cung cấp tính năng trích xuất toàn bộ cấu hình đang chạy ra thành file YAML mẫu chỉ với 1 cú click chuột.

Bước 1: Cài đặt Plugin

  1. Vào Manage Jenkins -> Plugins -> Available plugins.

  2. Tìm kiếm từ khóa: Configuration as Code (ID của plugin là configuration-as-code).

  3. Tích chọn và bấm Install.

Bước 2: Xuất cấu hình hiện tại ra YAML để làm mẫu (View Configuration)

  1. Sau khi cài xong, truy cập Manage Jenkins -> Configuration as Code (nằm ngay trong mục System Configuration).

  2. Bấm vào nút View Configuration (hoặc Download Configuration).

  3. Ngay lập tức, toàn bộ cấu hình Jenkins hiện tại của bạn (từ tên hệ thống, RBAC, danh sách Node Agent, SonarQube Server cho đến SSH Publisher) sẽ được dịch ngược từ các tệp .xml phức tạp sang định dạng YAML cực kỳ gọn gàng!

3. Viết tệp jenkins.yaml chuẩn Production cho hệ thống Monolith

Hãy gom toàn bộ những thành phần quan trọng nhất mà chúng ta đã thiết lập xuyên suốt chuỗi bài học (Hệ thống, Phân quyền RBAC Bài 28, Kết nối Agent Bài 31, Kho Credentials Bài 9, SonarQube Bài 13 và SSH Server Bài 22) vào một tệp duy nhất đặt tên là jenkins.yaml:

YAML

# ==============================================================================
# JENKINS CONFIGURATION AS CODE (JCasC) CHO HỆ THỐNG MONOLITH
# Đường dẫn mặc định: /var/jenkins_home/casc_configs/jenkins.yaml
# ==============================================================================

jenkins:
  systemMessage: "🚀 HỆ THỐNG CI/CD TRUNG TÂM DÀNH CHO DỰ ÁN MONOLITH (Quản lý tự động bởi JCasC - Vui lòng không sửa tay trên UI!)"
  
  # 1. Bảo vệ Jenkins Master: Đặt số luồng thực thi trên Master = 0 (Mọi việc nặng đẩy sang Agent - Bài 31)
  numExecutors: 0
  mode: EXCLUSIVE
  quietPeriod: 5
  scmCheckoutRetryCount: 2

  # 2. Cấu hình xác thực người dùng (Security Realm)
  securityRealm:
    local:
      allowsSignup: false
      users:
        - id: "admin"
          name: "System Administrator"
          password: "${JENKINS_ADMIN_PASSWORD}"
        - id: "hieu_techlead"
          name: "Hiếu (Tech Lead)"
          password: "${TECHLEAD_PASSWORD}"
        - id: "nam_dev"
          name: "Nam (Backend Developer)"
          password: "${DEV_PASSWORD}"

  # 3. Cấu hình Phân quyền RBAC tự động (Như đã thiết kế ở Bài 28)
  authorizationStrategy:
    roleBased:
      roles:
        global:
          - name: "admin"
            description: "Toàn quyền quản trị hệ thống"
            permissions:
              - "Overall/Administer"
            entries:
              - user: "admin"
          - name: "authenticated_member"
            description: "Quyền đăng nhập xem giao diện cơ bản"
            permissions:
              - "Overall/Read"
            entries:
              - user: "hieu_techlead"
              - user: "nam_dev"
        items:
          - name: "role_developer"
            pattern: "^monolith-(dev|ci)-.*"
            permissions:
              - "Job/Build"
              - "Job/Cancel"
              - "Job/Read"
              - "Job/Workspace"
            entries:
              - user: "nam_dev"
              - user: "hieu_techlead"
          - name: "role_techlead_prod"
            pattern: "^monolith-(prod|staging|emergency)-.*"
            permissions:
              - "Job/Build"
              - "Job/Cancel"
              - "Job/Configure"
              - "Job/Read"
              - "Run/Replay"
            entries:
              - user: "hieu_techlead"
          - name: "role_prod_viewer"
            pattern: "^monolith-prod-.*"
            permissions:
              - "Job/Read"
            entries:
              - user: "nam_dev"

  # 4. Khai báo máy chủ Worker Agent phân tán (Bài 31)
  nodes:
    - permanent:
        name: "monolith-worker-01"
        nodeDescription: "Máy chủ Worker chuyên Build & Test cho hệ thống Monolith"
        remoteFS: "/var/jenkins"
        numExecutors: 2
        labelString: "monolith-worker linux high-cpu"
        mode: EXCLUSIVE
        retentionStrategy: "always"
        launcher:
          ssh:
            host: "10.0.1.30"
            port: 22
            credentialsId: "jenkins-ssh-agent-credential"
            sshHostKeyVerificationStrategy: "nonVerifyingKeyVerificationStrategy"

# ==============================================================================
# QUẢN LÝ KHO KHÓA BÍ MẬT TẬP TRUNG (CREDENTIALS)
# Lưu ý: Không bao giờ viết mật khẩu rõ (plain-text) trong YAML, hãy đọc từ biến môi trường!
# ==============================================================================
credentials:
  system:
    domainCredentials:
      - credentials:
          - string:
              scope: GLOBAL
              id: "sonarqube-auth-token"
              secret: "${SONARQUBE_TOKEN}"
              description: "Token xác thực kết nối SonarQube Server (Bài 13)"
          - string:
              scope: GLOBAL
              id: "telegram-bot-token"
              secret: "${TELEGRAM_BOT_TOKEN}"
              description: "Token của Telegram Bot gửi thông báo CI/CD (Bài 19)"
          - string:
              scope: GLOBAL
              id: "telegram-chat-id"
              secret: "${TELEGRAM_CHAT_ID}"
              description: "ID nhóm chat Telegram nhận thông báo"
          - usernamePassword:
              scope: GLOBAL
              id: "docker-registry-credentials"
              username: "${REGISTRY_USER}"
              password: "${REGISTRY_PASS}"
              description: "Tài khoản đẩy Image lên Private Docker Registry (Bài 25)"
          - basicSSHUserPrivateKey:
              scope: GLOBAL
              id: "jenkins-ssh-agent-credential"
              username: "jenkins"
              description: "Khóa SSH kết nối từ Master sang Worker Agent (Bài 31)"
              privateKeySource:
                directEntry:
                  privateKey: "${AGENT_SSH_PRIVATE_KEY}"

# ==============================================================================
# CẤU HÌNH CÁC PLUGIN BÊN THỨ BA & GLOBAL TOOLS (UNCLASSIFIED & TOOL)
# ==============================================================================
unclassified:
  location:
    url: "https://jenkins.yourcompany.com/"
    adminAddress: "devops@yourcompany.com"

  # Cấu hình kết nối SonarQube Server (Bài 13)
  sonarGlobalConfiguration:
    buildWrapperEnabled: true
    installations:
      - name: "SonarQube-Main-Server"
        serverUrl: "http://10.0.1.20:9000"
        credentialsId: "sonarqube-auth-token"

  # Cấu hình danh sách máy chủ đích cho Publish Over SSH (Bài 22 & 24)
  publishOverSsh:
    hostConfigurations:
      - name: "Staging-Monolith-Server"
        hostname: "10.0.1.25"
        username: "deploy"
        remoteRootDir: "/var/www/monolith-app"
        port: 22
      - name: "Prod-Monolith-Server"
        hostname: "10.0.1.50"
        username: "deploy"
        remoteRootDir: "/var/www/monolith-app"
        port: 22

tool:
  sonarRunnerInstallation:
    installations:
      - name: "SonarScanner-CLI"
        properties:
          - installSource:
              installers:
                - sonarRunnerInstaller:
                    id: "5.0.1.3006"

4. Nguyên tắc bảo mật sống còn: Truyền biến bí mật vào jenkins.yaml qua Docker Compose

Nhìn vào tệp jenkins.yaml ở trên, bạn sẽ thấy tất cả các thông tin nhạy cảm đều được viết dưới dạng biến tham chiếu như ${JENKINS_ADMIN_PASSWORD}, ${SONARQUBE_TOKEN}, ${TELEGRAM_BOT_TOKEN}.

Tại sao phải làm như vậy? Vì tệp jenkins.yaml này sẽ được lưu trữ trên Git Repository của đội DevOps! Nhờ tách các mật khẩu ra thành biến môi trường (hoặc Docker Secrets), bạn có thể thoải mái đẩy tệp jenkins.yaml lên Git để cả nhóm cùng quản lý mà không lộ bất kỳ một ký tự mật khẩu nào.

Dưới đây là cách nâng cấp tệp docker-compose.yml của Jenkins Master (từ Bài 3) để tự động nạp tệp jenkins.yaml và truyền biến bí mật thông qua biến môi trường CASC_JENKINS_CONFIG:

YAML

version: '3.8'

services:
  jenkins-master:
    image: jenkins/jenkins:lts-jdk17
    container_name: jenkins-master
    restart: unless-stopped
    user: root
    ports:
      - "8080:8080"
      - "50000:50000"
    environment:
      # 1. Bỏ qua màn hình cài đặt thủ công ban đầu (Setup Wizard) khi dựng mới
      - JAVA_OPTS=-Djenkins.install.runSetupWizard=false
      
      # 2. Chỉ định đường dẫn chứa tệp cấu hình JCasC
      - CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs/jenkins.yaml

    # 3. Truyền toàn bộ mật khẩu thực tế từ tệp .env.jcasc bảo mật nằm trên máy chủ Host
    env_file:
      - ./secrets/.env.jcasc

    volumes:
      - /var/jenkins_home:/var/jenkins_home
      # Mount trực tiếp tệp jenkins.yaml từ kho Git trên Host vào bên trong Container (Chế độ chỉ đọc :ro)
      - ./casc_configs/jenkins.yaml:/var/jenkins_home/casc_configs/jenkins.yaml:ro
      - /var/run/docker.sock:/var/run/docker.sock

Nội dung tệp ./secrets/.env.jcasc nằm riêng trên máy chủ Host (được phân quyền chmod 600 và đưa vào .gitignore):

Đoạn mã

JENKINS_ADMIN_PASSWORD=SuperSecureAdminPass2026!
TECHLEAD_PASSWORD=TechLeadStrongPass2026!
DEV_PASSWORD=DevPass2026!
SONARQUBE_TOKEN=sqa_8f9d2a1b2c3d4e5f6g7h8i9j0k
TELEGRAM_BOT_TOKEN=7123456789:AAH_xyz1234567890abcdef
TELEGRAM_CHAT_ID=-1001987654321
REGISTRY_USER=harbor-robot-monolith
REGISTRY_PASS=HarborRobotSecretKey999

5. Khép kín vòng lặp tự động 100%: Tạo sẵn danh sách Jobs bằng Job DSL trong JCasC

Tệp jenkins.yaml ở mục 3 đã giúp chúng ta cấu hình toàn bộ hệ thống, phân quyền, mật khẩu và máy chủ Agent. Nhưng làm sao để khi dựng một máy chủ Jenkins mới tinh, các Pipeline như monolith-prod-pipeline, monolith-emergency-rollback và jenkins-system-housekeeping cũng tự động xuất hiện ngay trên màn hình trang chủ mà không cần ai bấm nút New Item?

Chúng ta chỉ cần cài thêm plugin Job DSL và bổ sung một khối jobs: nhỏ ở cuối tệp jenkins.yaml:

YAML

# Bổ sung vào cuối tệp jenkins.yaml để tự động khởi tạo các Folders và Pipelines cho hệ thống Monolith
jobs:
  - script: >
      folder('Monolith-System') {
          displayName('Hệ thống Monolith Core')
          description('Thư mục chứa toàn bộ các Pipelines CI/CD và Vận hành của dự án Monolith')
      }

      pipelineJob('Monolith-System/monolith-prod-pipeline') {
          displayName('1. Monolith Main CI/CD Pipeline')
          description('Pipeline tự động Test, Scan SonarQube, Build Docker và Blue/Green Deploy')
          definition {
              cpsScm {
                  scm {
                      git {
                          remote {
                              url('git@gitlab.yourcompany.com:backend/monolith-core.git')
                              credentials('jenkins-git-ssh-key')
                          }
                          branches('*/main', '*/staging', '*/develop')
                      }
                  }
                  scriptPath('Jenkinsfile')
              }
          }
      }

      pipelineJob('Monolith-System/monolith-emergency-rollback') {
          displayName('2. Emergency Production Rollback')
          description('Khôi phục khẩn cấp phiên bản Docker Image trên Production (Bài 27)')
          definition {
              cpsScm {
                  scm {
                      git {
                          remote {
                              url('git@gitlab.yourcompany.com:devops/jenkins-pipelines.git')
                              credentials('jenkins-git-ssh-key')
                          }
                          branches('*/main')
                      }
                  }
                  scriptPath('Jenkinsfile.rollback')
              }
          }
      }

6. Quy trình cập nhật cấu hình nóng (Hot-Reload) không làm gián đoạn bản Build

Khi vận hành thực tế với JCasC, quy trình làm việc của kỹ sư DevOps sẽ thay đổi hoàn toàn theo hướng chuyên nghiệp và an toàn tuyệt đối:

  1. Chỉnh sửa trên Git: Khi cần thêm một tài khoản Developer mới vào nhóm role_developer hoặc thêm máy chủ monolith-worker-02, bạn mở tệp jenkins.yaml, thêm vài dòng cấu hình và commit lên Git.

  2. Nạp lại cấu hình ngay lập tức (Zero-Downtime Reload):

    • Cách 1 (Qua giao diện Web): Vào Manage Jenkins -> Configuration as Code -> Bấm nút Reload existing configuration. Chỉ trong 0.5 giây, cấu hình mới có hiệu lực ngay lập tức mà không cần khởi động lại container Jenkins và không làm đứt bất kỳ bản build Monolith nào đang chạy!

    • Cách 2 (Tự động qua CLI/Pipeline): Tạo một Job nhỏ tự động lắng nghe Webhook của kho Git chứa tệp jenkins.yaml và gọi lệnh Groovy nạp lại cấu hình:

      Groovy

      io.jenkins.plugins.casc.ConfigurationAsCode.get().configure()
      

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí