加载带有环境变量的文件



我正在做一个简单的管道:

构建->登台->生产

我需要不同的环境变量的分期和生产,所以我试图变量。

sh 'source $JENKINS_HOME/.envvars/stacktest-staging.sh' 

但是它返回Not found

[Stack Test] Running shell script
+ source /var/jenkins_home/.envvars/stacktest-staging.sh
/var/jenkins_home/workspace/Stack Test@tmp/durable-bcbe1515/script.sh: 2: /var/jenkins_home/workspace/Stack Test@tmp/durable-bcbe1515/script.sh: source: not found

路径是正确的,因为我在通过ssh登录时运行相同的命令,并且它工作正常。

下面是管道的想法:

node {
    stage name: 'Build'
    // git and gradle build OK
    echo 'My build stage'
    stage name: 'Staging'
    sh 'source $JENKINS_HOME/.envvars/stacktest-staging.sh' // PROBLEM HERE
    echo '$DB_URL' // Expects http://production_url/my_db
    sh 'gradle flywayMigrate' // To staging
    input message: "Does Staging server look good?"    
    stage name: 'Production'
    sh 'source $JENKINS_HOME/.envvars/stacktest-production.sh'
    echo '$DB_URL' // Expects http://production_url/my_db
    sh 'gradle flywayMigrate' // To production
    sh './deploy.sh'
}

我该怎么办?

  • 我想不使用管道(但我将无法使用我的Jenkinsfile)。
  • 或者使用EnvInject Plugin(但我失去了我的舞台视图)为分期和生产制作不同的工作
  • 或者制作withEnv(但代码变大,因为今天我正在使用12个env变量)

从文件中加载环境变量的一种方法是加载Groovy文件。

例如:

  1. 假设在$JENKINS_HOME/中有一个groovy文件。
  2. 在这个文件中,您定义了两个要加载的环境变量

    env.DB_URL="hello"
    env.DB_URL2="hello2"
    
  3. 你可以使用

    加载
    load "$JENKINS_HOME/.envvars/stacktest-staging.groovy"
    

例如,下面是一个简短的管道脚本:

node {
   load "$JENKINS_HOME/.envvars/stacktest-staging.groovy"
   echo "${env.DB_URL}"
   echo "${env.DB_URL2}"
}

从评论到接受的答案

不要使用全局的'env',而是使用'withEnv'结构,例如:问题#9:不要设置env var与全局env在十大最佳实践詹金斯管道插件

在下面的例子中:VAR1是一个普通的java字符串(没有groovy变量扩展),VAR2是一个groovy字符串(因此变量'someGroovyVar'被扩展)。

传递的脚本是一个普通的java字符串,所以$VAR1和$VAR2是直接传递给shell的,echo访问的是环境变量VAR1和VAR2。

stage('build') {
    def someGroovyVar = 'Hello world'
    withEnv(['VAR1=VALUE ONE',
             "VAR2=${someGroovyVar}"
            ]) {
        def result = sh(script: 'echo $VAR1; echo $VAR2', returnStdout: true)
        echo result
    }
}

对于秘密/密码,你可以使用凭据绑定插件

的例子:

注意:CREDENTIALS_ID1是Jenkins设置中的注册用户名/密码秘密。

stage('Push') {
    withCredentials([usernamePassword(
                         credentialsId: 'CREDENTIALS_ID1',
                         passwordVariable: 'PASSWORD',
                         usernameVariable: 'USER')]) {
        echo "User name: $USER"
        echo "Password:  $PASSWORD"
    }
}

jenkisn控制台日志输出隐藏真实值:

[Pipeline] echo
User name: ****
[Pipeline] echo
Password:  ****

Jenkins和凭证是一个大问题,可能见:凭证插件

为了完整:大多数情况下,我们需要环境变量中的秘密,因为我们从shell脚本中使用它们,所以我们像下面这样组合withCredentials和withEnv:
stage('Push') {
    withCredentials([usernamePassword(
                         credentialsId: 'CREDENTIALS_ID1',
                         passwordVariable: 'PASSWORD',
                         usernameVariable: 'USER')]) {
        withEnv(["ENV_USERNAME=${USER}",
                 "ENV_PASSWORD=${PASSWORD}"
            ]) {
                def result = sh(script: 'echo $ENV_USERNAME', returnStdout: true)
                echo result
        }
    }
}

另一种方法来解决这个安装'管道实用程序步骤'插件,为我们提供了readProperties方法(参考请去链接https://jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#pipeline-utility-steps)在这个示例中,我们可以看到它们将键存储到一个数组中,并使用键来检索值。但在这种情况下,生产中的问题就像,如果我们在属性文件中添加任何变量,这个变量也需要添加到Jenkins文件的数组中。为了摆脱这种紧密耦合,我们可以以这样一种方式编写代码,以便Jenkins构建环境能够自动获取有关当前在Property文件中呈现的所有现有键的信息。下面是引用

的示例
def loadEnvironmentVariables(path){
    def props = readProperties  file: path
    keys= props.keySet()
    for(key in keys) {
        value = props["${key}"]
        env."${key}" = "${value}"
    }
} 

客户端代码看起来像

path = '\ABS_Output\EnvVars\pic_env_vars.properties'
loadEnvironmentVariables(path)

使用声明性管道,您可以在一行中完成(根据您的值更改path):

script {
  readProperties(file: path).each {key, value -> env[key] = value }
}

使用withEnv()传递由新行分隔的文件中的环境变量并强制转换为List:

writeFile file: 'version.txt', text: 'version=6.22.0'
withEnv(readFile('version.txt').split('n') as List) {
    sh "echo ${version}"
}

如果你正在使用Jenkins 2.0,你可以加载属性文件(包含所有必需的环境变量及其相应的值),并自动读取列出的所有环境变量,并将其注入到Jenkins提供的环境实体中。

这是一个执行上述操作的方法。

def loadProperties(path) {
    properties = new Properties()
    File propertiesFile = new File(path)
    properties.load(propertiesFile.newDataInputStream())
    Set<Object> keys = properties.keySet();
    for(Object k:keys){
    String key = (String)k;
    String value =(String) properties.getProperty(key)
    env."${key}" = "${value}"
    }
}
要调用此方法,我们需要将属性文件的路径作为字符串变量传递。例如,在使用groovy脚本的Jenkins文件中,我们可以调用
path = "${workspace}/pic_env_vars.properties"
loadProperties(path)

如果你有任何疑问请问我

这是一个外部化环境变量并在Jenkins管道执行中加载它们的完整示例。该管道是用声明式风格编写的。

stage('Reading environment variable defined in groovy file') {
            steps {
                script {
                    load "./pipeline/basics/extenvvariable/env.groovy"
                    echo "${env.env_var1}"
                    echo "${env.env_var2}"
                }
            }
        }

完整代码示例:https://github.com/dhruv-bansal/jenkins-pipeline-exploration/blob/master/pipeline/basics/extenvvariable/Jenkinsfile

变量从groovy文件中加载,仅与管道代码放在一起。https://github.com/dhruv-bansal/jenkins-pipeline-exploration/blob/master/pipeline/basics/extenvvariable/env.groovy

当您创建一个可以跨团队使用的通用管道时,此模式非常方便。您可以在groovy文件中外部化因变量,并且每个团队可以根据他们的生态系统定义它们的值。

另一个解决方案是使用自定义方法而不允许额外的权限,例如new Properties(),这会导致在允许之前出现此错误:

org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.util.Properties

或添加额外的插件方法,如readProperties

这里有一个方法,它读取一个名为env_vars的简单文件,格式如下:

FOO=bar
FOO2=bar
pipeline {
<... skipped lines ...>
    script {
        loadEnvironmentVariablesFromFile("env_vars")
        echo "show time! ${BAR} ${BAR2}"
    }
<... skipped lines ...>
}
private void loadEnvironmentVariablesFromFile(String path) {
    def file = readFile(path)
    file.split('n').each { envLine ->
        def (key, value) = envLine.tokenize('=')
        env."${key}" = "${value}"
    }
}

相关内容

  • 没有找到相关文章

最新更新