18.3.4 环境变量、参数化与凭据管理

环境变量、参数化与凭据管理是流水线“输入—控制—授权”的核心。建议明确作用域:全局(pipeline)、阶段(stage)、步骤(step),并通过统一命名与最小权限原则控制敏感信息的传播与日志暴露。

文章图片

环境变量作用域与示例#

Jenkinsfile 中常见三类作用域变量,注意覆盖顺序:步骤级 > 阶段级 > 全局。

// Jenkinsfile
pipeline {
  agent any
  environment {            // 全局变量
    APP_NAME = "demo-web"
    REGISTRY = "registry.example.com"
  }
  stages {
    stage('Build') {
      environment {        // 阶段变量覆盖
        BUILD_TYPE = "release"
      }
      steps {
        sh 'echo "APP=$APP_NAME REG=$REGISTRY TYPE=$BUILD_TYPE"'
        withEnv(["TAG=${env.BUILD_NUMBER}"]) {   // 步骤级临时变量
          sh 'echo "IMAGE=${REGISTRY}/${APP_NAME}:${TAG}"'
        }
      }
    }
  }
}

预期效果:控制台输出中可见 APP/REG/TYPE/IMAGE,步骤级 TAG 仅在 withEnv 内有效。

参数化构建与校验#

参数化构建用于多环境与多版本发布入口。建议启用白名单校验,并对高危操作增加确认参数。

// Jenkinsfile
pipeline {
  agent any
  parameters {
    choice(name: 'ENV', choices: ['dev', 'test', 'prod'], description: '发布环境')
    string(name: 'VERSION', defaultValue: '1.0.0', description: '发布版本')
    booleanParam(name: 'CONFIRM_PROD', defaultValue: false, description: '确认生产发布')
  }
  stages {
    stage('Validate') {
      steps {
        script {
          def allowed = ['dev','test','prod']
          if (!allowed.contains(params.ENV)) {
            error "ENV非法:${params.ENV}"
          }
          if (params.ENV == 'prod' && !params.CONFIRM_PROD) {
            error "生产发布必须确认 CONFIRM_PROD=true"
          }
        }
      }
    }
    stage('Show') {
      steps {
        sh "echo ENV=${params.ENV} VERSION=${params.VERSION}"
      }
    }
  }
}

凭据管理与注入(withCredentials)#

使用 Credentials Binding 插件,将凭据限制在步骤内,避免长时间驻留。

安装/启用插件(Jenkins CLI 示例)

# 需要已配置JENKINS_URL与API Token
java -jar jenkins-cli.jar -s http://jenkins.example.com/ \
  -auth admin:APITOKEN install-plugin credentials-binding -restart

Jenkinsfile 使用示例

// Jenkinsfile
pipeline {
  agent any
  stages {
    stage('Pull Code') {
      steps {
        withCredentials([usernamePassword(
            credentialsId: 'git-cred',
            usernameVariable: 'GIT_USER',
            passwordVariable: 'GIT_PASS'
        )]) {
          sh '''
            set -e
            git clone https://${GIT_USER}:${GIT_PASS}@git.example.com/repo/demo.git
          '''
        }
      }
    }
    stage('Deploy') {
      steps {
        withCredentials([string(credentialsId: 'kubeconfig', variable: 'KUBECONFIG_DATA')]) {
          sh '''
            set -e
            echo "$KUBECONFIG_DATA" > /tmp/kubeconfig
            export KUBECONFIG=/tmp/kubeconfig
            kubectl get ns
          '''
        }
      }
    }
  }
}

命令解释
- withCredentials:仅在闭包内注入环境变量,退出后自动清理。
- credentialsId:在 Jenkins 凭据管理器中创建的 ID。
- usernameVariable/passwordVariable:绑定为环境变量。

参数 + 环境 + 凭据综合示例#

pipeline {
  agent any
  parameters {
    choice(name: 'ENV', choices: ['test','prod'], description: '环境')
    string(name: 'IMAGE_TAG', defaultValue: 'latest', description: '镜像标签')
  }
  environment {
    APP_NAME = "api-service"
    REGISTRY = "registry.example.com"
  }
  stages {
    stage('Validate') {
      steps {
        script {
          if (params.ENV == 'prod' && params.IMAGE_TAG == 'latest') {
            error "生产环境禁止使用latest标签"
          }
        }
      }
    }
    stage('Push Image') {
      steps {
        withCredentials([usernamePassword(
          credentialsId: 'harbor-cred',
          usernameVariable: 'H_USER',
          passwordVariable: 'H_PASS'
        )]) {
          sh '''
            set -e
            echo "$H_PASS" | docker login -u "$H_USER" --password-stdin registry.example.com
            docker tag ${APP_NAME}:${IMAGE_TAG} ${REGISTRY}/${APP_NAME}:${IMAGE_TAG}
            docker push ${REGISTRY}/${APP_NAME}:${IMAGE_TAG}
          '''
        }
      }
    }
  }
}

常见排错#

  1. 凭据变量为空
    - 现象:/bin/sh: H_USER: unbound variable
    - 排查:确认 credentialsId 是否正确、凭据作用域是否授权到当前 Job。
  2. 参数不生效
    - 现象:params.ENV 为空
    - 排查:流水线未“参数化构建”,检查是否重新运行并选择参数。
  3. 日志泄漏
    - 现象:控制台输出明文密码
    - 排查:确保使用 withCredentials,避免 echo $PASS,启用 Mask Passwords。

练习#

  1. 创建一个参数化流水线,限制 prod 只能发布 v1.* 版本。
  2. 使用 withEnv 实现仅在某个阶段临时设置 JAVA_HOME
  3. 绑定 SSH 私钥凭据,执行 ssh -i 远程执行 hostname