Jenkins Learn
03. Jobs & cấu hình build

Biến môi trường Jenkins

Chọn đúng nguồn, scope và precedence của Jenkins environment variables; override an toàn và bảo vệ secret trong Pipeline.

Biến môi trường giúp Jenkins truyền cấu hình và metadata vào process build, nhưng cùng một tên có thể xuất hiện ở controller, agent, job và Jenkinsfile. Trang này chỉ ra giá trị đi từ đâu, scope nào thắng tại một process cụ thể và khi nào phải dùng Jenkins Credentials thay vì environment.

Mục lục

Mô hình và hai namespace

Controller, agent và process shell

Controller điều phối build và tạo context Pipeline. Agent nhận executor, workspace và chạy sh, bat hoặc powershell. Khi Jenkins gọi một step process, nó tạo một environment cho process đó từ context đang hiệu lực trên agent. Vì vậy, biến của service controller không tự động là biến của shell trên agent.

Ví dụ JENKINS_URL có thể do controller cung cấp cho build, còn PATH của process lại phụ thuộc OS, image hoặc cấu hình node/agent. WORKSPACE chỉ có ý nghĩa sau khi Jenkins đã cấp agent và workspace. Không chuyển workload lên controller chỉ vì một biến chỉ có ở đó; hãy chọn agent có label và trust boundary phù hợp. Xem Kiến trúc Jenkins và Tổng quan Jenkins Agent.

Biến built-in và biến custom

Built-in variables là metadata Jenkins hoặc plugin đặt theo context, như BUILD_NUMBER, BUILD_TAG, JOB_NAME, NODE_NAME, WORKSPACE, JENKINS_URL và, với Multibranch Pipeline khi nguồn SCM cung cấp, BRANCH_NAME. Đừng giả định mọi biến built-in luôn có: một job không có workspace chưa có WORKSPACE; Freestyle, Pipeline và plugin Branch Source cũng có thể cung cấp context khác nhau. Tra Global Variable Reference trên controller để xem biến/step của chính instance.

Custom variables là tên đội tự đặt, ví dụ APP_COMPONENT=reports-api hoặc LOG_LEVEL=info. Dùng tên mô tả trách nhiệm, tránh ghi đè các tên Jenkins/tool/OS phổ biến như PATH, HOME, JAVA_HOME nếu chưa hiểu hậu quả. Thiết lập custom variable ở scope hẹp nhất đáp ứng nhu cầu và ghi owner của những biến global.

Parameters: params và environment của build

Jenkins export build parameters tiêu chuẩn thành environment variables khi build bắt đầu, nên step process thường có thể đọc DEPLOY_TIER bằng $DEPLOY_TIER (POSIX shell), %DEPLOY_TIER% (cmd.exe) hoặc $env:DEPLOY_TIER (PowerShell). Cùng giá trị đó cũng có qua params.DEPLOY_TIER trong Pipeline. Không cần tự export một parameter tiêu chuẩn chỉ để shell thấy nó.

Hai API phục vụ hai mục đích khác nhau. params.NAME giữ giá trị parameter theo kiểu/ngữ nghĩa parameter cho Groovy/Pipeline, chẳng hạn params.DRY_RUN là boolean. env.NAME là biểu diễn chuỗi trong Pipeline environment; process chỉ nhận biểu diễn này. Ví dụ params.DRY_RUN nên được dùng trong condition Groovy, còn shell phải so sánh chuỗi "true"/"false" nếu thật sự cần đọc $DRY_RUN.

Parameter là một nguồn baseline của environment build, không phải một tầng env tách biệt. Nếu tên parameter trùng với environment, withEnv hoặc biến do plugin inject, giá trị env.NAME/process thấy có thể bị overlay bởi scope gần step hơn. params.NAME vẫn là input đã chọn. Jenkins documentation bảo đảm parameter được export khi build bắt đầu và environment áp dụng cho các step theo scope, nhưng không quy định một precedence phổ quát cho mọi plugin hay parameter type tùy biến. Tránh collision bằng tên riêng; nếu không tránh được, kiểm chứng trên controller/version/plugin bằng lab ở dưới.

Built-in không phải dữ liệu tin cậy từ người dùng

Metadata build hữu ích để định danh lần chạy, nhưng branch, commit message, tên job hiển thị, parameter và nội dung repository vẫn có thể bị kiểm soát bởi người không đáng tin ở các mô hình job khác nhau. Không ghép chúng trực tiếp thành command, URL, path hay chính sách authorization.

Nguồn biến môi trường

Bảng nguồn scope và lifecycle

Không có một nguồn duy nhất cho environment. Bảng này mô tả nơi một giá trị thường được tạo và nơi nó có thể được quan sát; plugin hoặc loại job có thể bổ sung biến khác.

NguồnVí dụScope thường gặpLưu ý precedence và lifecycle
Controller/systemservice environment, Java/system setting, Global properties → Environment variablesController process hoặc build mới nhận global propertyService/JVM setting có consumer riêng và thường cần restart controller. Global property không phải nơi chứa secret.
Node/agentimage/host OS, node property, PATH, CA nội bộAgent hoặc process kế thừa trên agent đóController không suy ra được tool/PATH của agent. Image/host đổi có thể chỉ thấy ở allocation/process mới.
Folder/jobjob property, Folder property hoặc plugin inject environmentJob/folder và build của item con theo plugin/cấu hìnhPhạm vi, thứ tự và khả năng override phụ thuộc plugin; ghi rõ owner và không dựa vào UI field không được kiểm chứng.
Parametersparams.DEPLOY_TIER, params.DRY_RUN; $DEPLOY_TIER trong shellInput build và baseline environment được export lúc build bắt đầuparams.NAME là API Pipeline theo kiểu/ngữ nghĩa parameter; env.NAME/process nhận chuỗi. environment, withEnv hoặc plugin có thể overlay khi trùng tên; kiểm chứng collision trên instance. Validate và map allowlist trước side effect.
Declarative environmentPipeline-level LOG_LEVEL, stage-level LOG_LEVELToàn Pipeline hoặc một stageScope gần process hơn che scope ngoài theo cấu trúc Pipeline. Dùng cho cấu hình không nhạy cảm.
withEnvwithEnv(['LOG_LEVEL=trace'])Closure/block ngắnOverride tạm cho step bên trong; hết block là trở lại giá trị trước đó.
Tool installerstools { jdk 'temurin-21.0.6' }, tool plugin thêm PATHAgent/stage khi tool được resolveTool name là contract; installer có thể tải code trên agent. Pin version và kiểm tra source/provenance.
Credentials BindingwithCredentials([...]) hoặc credentials('id')Closure hoặc environment của Pipeline/stageĐây là capability nhạy cảm, không phải cấu hình thông thường. Thu hẹp scope và không in environment.

environment không thay thế cấu hình tool. Ví dụ, nối một đường dẫn tùy ý vào PATH không cài JDK, không xác minh checksum và không tạo quyền dùng tool. Với tool dùng chung, xem Cấu hình hệ thống Jenkins; với labels và executor, xem Labels & Executors.

Thay đổi cấu hình, restart và build đang chạy

Một build đang chạy không phải bảng điều khiển để thay đổi environment giữa chừng. Nó có thể đã tạo process environment hoặc đã đi qua stage cần biến đó. Hãy trigger một build sandbox mới để xác minh thay đổi thay vì suy ra từ build cũ.

Thay đổiThường cần restart?Cách xác minh an toàn
Global property lưu từ UI/JCasCThường không; build mới là đối tượng kiểm traChạy job sandbox mới trên đúng agent và chỉ in marker không nhạy cảm.
Node property, image hoặc host environmentTùy launcher, image và tiến trình agentDrain/refresh agent theo quy trình, xác nhận node online rồi chạy canary.
Service environment hoặc JVM -D của controllerCó; restart/recreate controllerChange window, health check controller/agent và rollback đã chuẩn bị.
environment/withEnv trong JenkinsfileKhông; có hiệu lực khi revision mới chạyReview revision, validate syntax và chạy build lab.
Tool definition/installerKhông nhất thiết cho controller; build sau mới resolveXem log của đúng agent và chạy --version không nhạy cảm.

Không có precedence phổ quát cho mọi plugin

Bảng precedence bên dưới áp dụng cho cùng một tên environment mà process Pipeline nhận. System property Java, option plugin, parameter và configuration field của tool có consumer khác nhau; đừng đổi tên một giá trị giữa các lớp với hy vọng nó sẽ tự ghi đè.

Scope, precedence và override

Sơ đồ precedence của một process

Khi cùng tên LOG_LEVEL được đặt ở nhiều lớp, hãy đọc từ ngoài vào trong. Scope gần step process nhất sẽ che giá trị của scope ngoài trong thời gian nó hiệu lực.

direction: down
baseline: "Controller/global + node/agent\nparameter export lúc bắt đầu build"
env: "Baseline env.LOG_LEVEL\nprocess LOG_LEVEL"
pipeline: "Pipeline environment\nLOG_LEVEL=info"
stage: "Stage environment\nLOG_LEVEL=debug"
overlay: "withEnv\nLOG_LEVEL=trace"
process: Process nhận LOG_LEVEL=trace
params: "params.LOG_LEVEL\nAPI giữ input parameter\nkhông bị env overlay"
baseline -> env -> pipeline -> stage -> overlay -> process
params -> baseline: Export ban đầu {style.stroke-dash: 4}
Controller/global + node/agentparameter export lúc bắt đầu buildBaseline env.LOG_LEVELprocess LOG_LEVELPipeline environmentLOG_LEVEL=infoStage environmentLOG_LEVEL=debugwithEnvLOG_LEVEL=traceProcess nhận LOG_LEVEL=traceparams.LOG_LEVELAPI giữ input parameterkhông bị env overlay Export ban đầu
Controller/global + node/agentparameter export lúc bắt đầu buildBaseline env.LOG_LEVELprocess LOG_LEVELPipeline environmentLOG_LEVEL=infoStage environmentLOG_LEVEL=debugwithEnvLOG_LEVEL=traceProcess nhận LOG_LEVEL=traceparams.LOG_LEVELAPI giữ input parameterkhông bị env overlay Export ban đầu
Sơ đồ precedence của một process

Sơ đồ là mô hình cho Declarative/Pipeline context thông dụng, không phải cam kết của mọi plugin inject environment. Đối với job/folder/plugin, xác minh bằng một build lab có tên marker mới thay vì ghi đè biến hệ thống quan trọng.

Quy tắc thực hành

  1. Agent/node và global property tạo baseline cho process, nhưng không đáng tin để che cấu hình job mà không có owner.
  2. Pipeline-level environment áp dụng trong Pipeline. Stage-level environment che cùng tên trong stage đó.
  3. withEnv che giá trị bên ngoài chỉ trong closure. Đây là lựa chọn rõ ràng cho override tạm.
  4. Không dùng env.NAME = '...' để cố sửa giá trị đã khai báo bằng Declarative environment; behavior này dễ gây hiểu nhầm và không phải cách override tường minh. Đặt một tên runtime mới đã validate, hoặc dùng withEnv.
  5. Parameter tiêu chuẩn vừa có qua params.NAME vừa được export thành env.NAME/process environment khi build bắt đầu. params.NAME giữ input theo kiểu parameter, còn env.NAME là chuỗi và có thể bị environment, withEnv hoặc plugin overlay khi trùng tên. Đừng suy luận collision từ tên giống nhau: đặt tên riêng hoặc quan sát cả ba bề mặt trên controller của bạn.
  6. Credentials binding có thể đưa secret vào environment của scope binding, nhưng không là một tầng precedence để lạm dụng. Chỉ bind ngay cạnh công cụ cần capability đó.

Bảng chẩn đoán precedence

Tình huốngGiá trị process thấySau scopeHướng làm an toàn
Pipeline LOG_LEVEL=info, stage LOG_LEVEL=debugdebug trong stageTrở về info khi stage kết thúcGiữ override stage ngắn và theo mục đích.
Stage debug, withEnv(['LOG_LEVEL=trace'])trace trong closureTrở về debugDùng withEnv, không sửa global property.
Parameter LOG_LEVEL='trace', chưa có collisionparams.LOG_LEVEL là input; env.LOG_LEVEL và shell thường nhận chuỗi trace từ parameter exportHết buildKhông cần tự export parameter tiêu chuẩn; vẫn không đưa input tự do vào command/path.
Parameter LOG_LEVEL trùng Declarative environment hoặc plugin injectionparams.LOG_LEVEL vẫn là input; env.LOG_LEVEL/shell phụ thuộc overlay và version/pluginTheo scope overlayTránh trùng tên. Nếu bắt buộc, dùng marker vô hại và quan sát params, env, process trong lab; không coi đây là precedence phổ quát.
Tool thêm đường dẫn vào PATHPATH của stage/process có thể được tool sửaTheo scope tool/stepDùng tool definition đã pin version; không hard-code path theo máy.
Một plugin/job property inject biến trùng tênPhụ thuộc thứ tự/plugin đã càiPhụ thuộc pluginĐổi sang tên custom có namespace và kiểm chứng bằng lab.

Đọc và truyền giá trị đúng cách

Shell process khác Jenkins env

Trong Groovy/Pipeline, đọc environment bằng env.NAME; đọc parameter bằng params.NAME. Parameter tiêu chuẩn cũng được Jenkins export thành environment lúc build bắt đầu, nên Unix shell có thể đọc $NAME hoặc ${NAME} mà không cần export lại. env không phải một map Java/Groovy chung để mọi process đang chạy cùng thấy thay đổi; một assignment Pipeline chỉ ảnh hưởng các step được tạo sau trong scope phù hợp. Khi tên trùng nhau, params.NAME diễn tả input parameter còn env.NAME là chuỗi effective environment ở scope hiện tại.

script {
  def tier = params.DEPLOY_TIER
  if (!(tier in ['sandbox', 'staging'])) {
    error('DEPLOY_TIER is not allowlisted')
  }
  env.RUN_MODE = tier == 'staging' ? 'preview' : 'sandbox'
}

sh 'printf "mode=%s build=%s\\n" "$RUN_MODE" "$BUILD_NUMBER"'

Mẫu chỉ map một parameter từ allowlist sang giá trị cố định và in metadata vô hại. Không lấy parameter tự do để đặt PATH, label, credential ID, hostname hay command.

Quote và interpolation

Groovy interpolation xảy ra trước khi Jenkins gửi script tới shell. Shell interpolation xảy ra khi shell chạy. Giữ hai lớp này tách biệt, đặc biệt trong scope có credential.

Mục tiêuMẫu phù hợpTránh
Để shell Unix mở rộng biến environmentsh 'printf "%s\\n" "$APP_COMPONENT"'sh "... ${env.APP_COMPONENT} ..." khi không cần Groovy.
Script nhiều dòngsh '''\nset -eu\nprintf '%s\\n' "$RUN_MODE"\n'''Triple double quote chứa $TOKEN hoặc ${TOKEN}.
Đưa giá trị đã validate vào Groovy logicdef enabled = params.DRY_RUNNhét input tự do vào sh "...${params.INPUT}...".
Windows Command Promptbat 'echo APP_COMPONENT=%APP_COMPONENT%'Sao chép $APP_COMPONENT từ sh sang bat.
PowerShellpowershell '$env:APP_COMPONENT'Giả định %APP_COMPONENT% hoạt động trong PowerShell.

Single quote ở Groovy không tự làm dữ liệu không tin cậy trở nên an toàn: nó chỉ tránh Groovy nội suy. Input tự do vẫn không được đưa vào script, URL, path hoặc command. Trong shell Unix, luôn quote expansion như "$NAME" khi nó là dữ liệu, để space và glob không làm đổi argument. Trên Windows, quy tắc escape khác giữa cmd.exe và PowerShell; chọn đúng step/shell rồi kiểm tra trên agent Windows thực tế.

Null boolean path và khác biệt hệ điều hành

Environment là chuỗi. env.FLAG = false trở thành chuỗi như "false"; trong Groovy, chuỗi không rỗng thường là truthy. Đọc boolean từ params qua params.DRY_RUN, hoặc so sánh tường minh với chuỗi đã được chuẩn hóa khi nguồn thực sự là environment.

if (params.DRY_RUN) {
  echo 'Dry run is enabled.'
}

if ((env.FEATURE_FLAG ?: '').toLowerCase() == 'true') {
  echo 'Feature flag is explicitly true.'
}

env.MISSING có thể là null trong Groovy, còn shell với set -u sẽ lỗi khi mở rộng biến chưa đặt. Dùng default có chủ đích, ví dụ ${OPTIONAL_NAME:-} trong POSIX shell, nhưng đừng biến default thành cách bỏ qua một config bắt buộc: kiểm tra test -n "$REQUIRED_NAME" và fail sớm khi cần.

PATH dùng dấu : trên Unix và ; trên Windows; case sensitivity của tên biến cũng phụ thuộc OS/tool. Đường dẫn có space cần được quote. Không tách/ghép PATH bằng một rule dùng cho cả sh, bat và PowerShell. Đặt toolchain trong image, node configuration hoặc tools đã review thay vì dựa vào path local của một agent.

Jenkinsfile mẫu an toàn

Mẫu Declarative này thể hiện parameter, Pipeline/stage environment, withEnv và xử lý boolean. Nó không checkout, không gọi network, không dùng credential và chỉ in metadata không nhạy cảm. Cần một agent Unix có label placeholder sandbox-linux; thay label này bằng pool sandbox của bạn, không phải controller.

pipeline {
  agent none

  options {
    skipDefaultCheckout(true)
    timeout(time: 3, unit: 'MINUTES')
  }

  parameters {
    choice(
      name: 'DEPLOY_TIER',
      choices: ['sandbox', 'staging'],
      description: 'Lựa chọn mô phỏng; không cấp quyền deploy.'
    )
    booleanParam(
      name: 'DRY_RUN',
      defaultValue: true,
      description: 'Chỉ điều khiển output sandbox.'
    )
    choice(
      name: 'LAB_PARAM_MARKER',
      choices: ['parameter-baseline'],
      description: 'Marker vô hại để quan sát params, env và process environment.'
    )
    choice(
      name: 'LAB_COLLISION_MARKER',
      choices: ['parameter-baseline'],
      description: 'Marker vô hại để quan sát collision với stage environment.'
    )
  }

  environment {
    APP_COMPONENT = 'example-component'
    LOG_LEVEL = 'info'
  }

  stages {
    stage('Validate context') {
      agent { label 'sandbox-linux' }
      steps {
        script {
          def tiers = ['sandbox': 'sandbox', 'staging': 'preview']
          def selected = tiers[params.DEPLOY_TIER]
          if (selected == null) {
            error('DEPLOY_TIER is not allowlisted')
          }
          env.RUN_MODE = params.DRY_RUN ? "${selected}-dry-run" : "${selected}-check"
          if (params.LAB_PARAM_MARKER != 'parameter-baseline') {
            error('LAB_PARAM_MARKER is not allowlisted')
          }
          echo "params.LAB_PARAM_MARKER=${params.LAB_PARAM_MARKER}"
          echo "env.LAB_PARAM_MARKER=${env.LAB_PARAM_MARKER}"
        }
        sh '''
          set -eu
          test -n "$RUN_MODE"
          test "$LAB_PARAM_MARKER" = 'parameter-baseline'
          printf 'process.LAB_PARAM_MARKER=%s\\n' "$LAB_PARAM_MARKER"
          printf 'component=%s mode=%s level=%s build=%s\\n' \\
            "$APP_COMPONENT" "$RUN_MODE" "$LOG_LEVEL" "$BUILD_NUMBER"
        '''
      }
    }

    stage('Observe parameter collision') {
      agent { label 'sandbox-linux' }
      environment {
        LAB_COLLISION_MARKER = 'declarative-overlay'
      }
      steps {
        script {
          echo "params.LAB_COLLISION_MARKER=${params.LAB_COLLISION_MARKER}"
          echo "env.LAB_COLLISION_MARKER=${env.LAB_COLLISION_MARKER}"
        }
        sh '''
          set -eu
          printf 'process.LAB_COLLISION_MARKER=%s\\n' "$LAB_COLLISION_MARKER"
        '''
      }
    }

    stage('Observe short override') {
      agent { label 'sandbox-linux' }
      environment {
        LOG_LEVEL = 'debug'
      }
      steps {
        withEnv(['LOG_LEVEL=trace']) {
          sh '''
            set -eu
            test "$LOG_LEVEL" = 'trace'
            printf 'inside-withEnv=%s\\n' "$LOG_LEVEL"
          '''
        }
        sh '''
          set -eu
          test "$LOG_LEVEL" = 'debug'
          printf 'after-withEnv=%s\\n' "$LOG_LEVEL"
        '''
      }
    }
  }

  post {
    always {
      echo 'Sandbox example finished; no credential, deploy, artifact, or network action was used.'
    }
  }
}

RUN_MODE được tạo từ allowlist, boolean và chuỗi cố định. DEPLOY_TIER không được nội suy vào shell. LAB_PARAM_MARKER chứng minh cùng parameter tiêu chuẩn xuất hiện qua params, env và process environment. LAB_COLLISION_MARKER chỉ quan sát collision: params phải còn input đã chọn, còn env/process phản ánh overlay effective của stage trên Jenkins đang chạy. LOG_LEVEL là ví dụ override vô hại: stage che Pipeline và withEnv che stage; test sau closure chứng minh giá trị stage trở lại.

Để chọn cấu trúc Pipeline, xem Declarative Pipeline hoặc Scripted Pipeline. Parameter, environment và withEnv được giải thích bổ sung tại Environment & Parameters.

Secret và credentials

Environment không phải secret store

Không đặt token, mật khẩu, private key, connection string nhạy cảm hoặc secret bootstrap trong Global properties, node property, folder/job environment, Jenkinsfile, parameter hoặc file .env commit vào SCM. Những nguồn này có thể bị nhiều job, process con, plugin, log/diagnostic, workspace, backup hoặc người có quyền cấu hình quan sát.

Dùng Jenkins Credentials với credential ID có nghĩa rõ, scope folder/job nhỏ nhất và permission tối thiểu. Tách token đọc source, token publish artifact và credential deploy. Một parameter tên TARGET=production không cấp authorization và không được dùng để chọn credential ID tùy ý. Binding credential là quyết định tin cậy cả Jenkinsfile, Shared Library, agent image, process con và source kích hoạt stage.

Binding ngắn hạn và giới hạn masking

withCredentials của Credentials Binding nạp credential vào closure hẹp. Dùng single quote/triple single quote để shell mới mở rộng biến, tránh Groovy interpolation của secret.

withCredentials([
  string(credentialsId: 'placeholder-service-token', variable: 'SERVICE_TOKEN')
]) {
  sh '''
    set +x
    # Công cụ đã review đọc SERVICE_TOKEN từ environment.
    ./tool --use-environment-token
  '''
}

placeholder-service-token chỉ là credential ID placeholder, không phải giá trị secret. Đoạn này không phải lab chạy được nếu ID/tool chưa tồn tại. Trong Pipeline thật, binding chỉ bao quanh command cần capability; không chuyển secret thành argument, URL hoặc file output nếu công cụ có cách đọc environment/file descriptor an toàn hơn.

Masking không phải ranh giới bảo mật

Jenkins cố gắng mask secret đã biết trong Console Output, nhưng không ngăn code đã nhận secret gửi ra network, encode/biến đổi nó, ghi nó vào file/artifact/cache, hoặc để process khác cùng agent đọc environment/process arguments. Không dùng echo, printenv, env, set, set -x, debug dump, artifact glob rộng hay report toàn workspace trong scope binding.

Tránh Groovy interpolation, echo, command-line/proc argv, URL, log, artifact, cache, test report và notification chứa secret. Không chạy PR/fork hoặc source không tin cậy trên agent có credential phát hành; áp dụng least privilege cho folder/job, identity agent, filesystem và egress. Nếu nghi ngờ lộ lọt, dừng sử dụng credential và rotate/thu hồi theo incident process; xóa log không thu hồi bản sao đã bị đọc. Xem quy trình và file binding tại Credentials trong Pipeline.

Lab sandbox: quan sát override vô hại

Chuẩn bị và Jenkinsfile

Lab không cần repository, credential, artifact, network hay secret. Cần controller sandbox, agent Unix online với label sandbox-linux, shell sh và quyền tạo Pipeline job. Đặt executor built-in node/controller là 0 trên môi trường production; không dùng controller thay agent để làm lab chạy nhanh hơn.

  1. Tạo một Pipeline job tạm tên environment-scope-lab và dán Jenkinsfile ở phần Jenkinsfile mẫu an toàn.
  2. Mở Pipeline Syntax hoặc Declarative Directive Generator trên controller để xác nhận plugin/cú pháp. Thay sandbox-linux chỉ bằng label của pool lab tách biệt.
  3. Chạy lần đầu với DEPLOY_TIER=sandbox, DRY_RUN=true và giữ hai marker ở default. Đọc riêng ba dòng params.LAB_PARAM_MARKER, env.LAB_PARAM_MARKER, process.LAB_PARAM_MARKER; không thêm env, printenv hay secret để debug.
  4. Ghi ba dòng LAB_COLLISION_MARKER trong stage collision. params phải biểu diễn input parameter-baseline; đối chiếu env và process với declarative-overlay để ghi nhận overlay trên Jenkins/version plugin của bạn. Không dùng quan sát này để suy ra precedence cho plugin hay parameter type khác.
  5. Chạy lần hai với DEPLOY_TIER=staging và DRY_RUN=false. So sánh mode với build đầu, rồi quan sát hai dòng inside-withEnv và after-withEnv.
  6. Xóa job lab khi không còn cần. Vì mẫu không checkout/tạo artifact/credential, cleanup chỉ cần xóa job sandbox theo policy của đội; không xóa history hay workspace của job khác.

Kết quả mong đợi và cleanup

Thao tácKết quả mong đợiĐiều được chứng minh
Build sandbox, dry runmode=sandbox-dry-run; level=info tại stage đầuParameter được map trong Jenkinsfile sau validation; không đi vào command tự do.
LAB_PARAM_MARKER không trùng tênBa dòng params, env, process cùng là parameter-baselineParameter tiêu chuẩn có API params và được export thành environment cho step process.
LAB_COLLISION_MARKER trùng stage environmentparams là parameter-baseline; ghi nhận env và process effective trên instanceCollision có thể có overlay; không khẳng định precedence phổ quát cho plugin/type tùy biến.
Build staging, không dry runmode=preview-check; không deploy/networkBoolean được xử lý như boolean, choice đi qua allowlist.
Trong withEnvinside-withEnv=traceClosure gần process che stage-level value.
Sau withEnvafter-withEnv=debug; build SUCCESSOverride kết thúc khi closure kết thúc; stage value được khôi phục.
CleanupJob tạm được xóa hoặc giữ theo retention lab; không có artifact/secret cần thu hồiLab không tạo dữ liệu nhạy cảm hay chạm production.

Debug theo tên marker, không dump environment

Khi cần biết scope, thêm một custom marker vô hại như LAB_ENV_MARKER=scope-test và chỉ in đúng marker đó. Điều này giảm rủi ro vô tình lộ token, URL nội bộ hoặc metadata nhạy cảm trong toàn bộ environment.

Troubleshooting

Triệu chứngNguyên nhân khả dĩCách xử lý có bằng chứng
Biến rỗng trong shSai scope, agent chưa được cấp, nhầm params với env, hoặc tên/case khácKiểm tra stage/agent, đọc đúng namespace và in một marker không nhạy cảm.
WORKSPACE rỗng hoặc không đúngCode chạy trước allocation, stage khác agent, hoặc không có workspace contextXác minh NODE_NAME/stage/queue; không giả định workspace chia sẻ giữa agent.
withEnv không thấy sau closureĐây là behavior đúng: closure đã kết thúcĐặt override ở block bao đúng step cần nó, không mở rộng thành global.
env.NAME = không đổi giá trị DeclarativeValue được khai báo ở environment hoặc bị scope gần hơn cheDùng withEnv cho override tạm, hoặc tạo biến runtime tên mới sau validation.
Build nhận tool/version saiAgent/image khác, tool name không khớp hoặc PATH bị sửa thủ côngKiểm tra label, --version, tool definition và installer log trên đúng agent.
Parameter tiêu chuẩn không thấy trong shellSai tên/case, build không dùng parameter chuẩn, hoặc overlay/plugin đã đổi cùng tênKiểm tra params.NAME, env.NAME và một process marker trong build mới; không tự export mù quáng hoặc dump toàn environment.
Secret hiện **** nhưng vẫn có rủi roMasking che console có giới hạn, không chặn exfiltration/file/processThu hẹp binding, dừng debug dump, đánh giá artifact/log và rotate khi nghi ngờ lộ.
Build chờ hoặc chạy trên agent saiLabel/executor/policy không khớpĐọc Build Queue và node labels trước khi đổi agent hay controller executor.

Checklist

  • Tôi biết biến này đến từ controller/system, agent, job/folder, parameter, Jenkinsfile, tool hay credential binding.
  • Mỗi custom environment có owner, mục đích và scope hẹp nhất; global property chỉ chứa cấu hình không nhạy cảm.
  • Tôi phân biệt params.NAME (input theo kiểu parameter), env.NAME (chuỗi effective) và biến process shell; biết parameter tiêu chuẩn được export lúc build bắt đầu.
  • Tôi tránh collision giữa parameter, Pipeline/stage environment, withEnv và plugin injection; khi cần, tôi kiểm chứng params/env/process trên instance thay vì giả định precedence phổ quát.
  • Pipeline-level, stage-level và withEnv không dùng chung tên vô tình; override tạm nằm trong closure ngắn.
  • Tôi không dùng env.NAME = để sửa hằng Declarative và không dùng precedence để vượt policy/authorization.
  • Built-in variable chỉ được dùng khi context thực sự có; controller/agent và workspace được xác minh trên build mới.
  • Shell script dùng quote đúng, không Groovy-interpolate secret; boolean/null/path được xử lý tường minh và theo OS.
  • Toolchain được quản lý bằng image/node/tool definition đã review, pin version; không sửa PATH mù quáng.
  • Secret không nằm trong environment global/job, parameter, Jenkinsfile, log, proc argv, URL, artifact, cache hoặc report.
  • Credential dùng ID, scope folder/job nhỏ, withCredentials ngắn, least privilege và agent tách khỏi workload không tin cậy.
  • Tôi không coi masking là bảo mật; có quy trình rotate/thu hồi và cleanup khi có nghi ngờ lộ lọt.
  • Lab đã xác minh precedence bằng marker vô hại, có kết quả mong đợi và cleanup rõ ràng.

Nguồn Jenkins chính thức

Đọc tiếp

On this page