私は単純なパイプラインをやっています:
ビルド->ステージング->本番
ステージングとプロダクションには異なる環境変数が必要なので、source変数にしようとしています。
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'
}
私は何をすべきか?
ファイルから環境変数をロードできる1つの方法は、Groovyファイルをロードすることです。
例えば:
このファイル内で、ロードする2つの環境変数を定義します
env.DB_URL="hello"
env.DB_URL2="hello2"
次に、これを使用してロードできます
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を参照してください: トップ10ベストプラクティスjenkins pipeline plugin
次の例では、VAR1はプレーンJava文字列(groovy変数展開なし)、VAR2はgroovy文字列です(変数 'someGroovyVar'は展開されます)。
渡されたスクリプトは、プレーンなJava文字列であるため、$ VAR1および$ VAR2は文字通りシェルに渡され、エコーは環境変数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 binding plugin を使用できます
例:
注: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と資格情報は大きな問題です。おそらく以下を参照してください: credentials plugin
完全を期すために:ほとんどの場合、シェルスクリプトから使用するため、環境変数にシークレットが必要です。そのため、次のように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メソッドを提供する「Pipeline Utility Steps」プラグインをインストールします(参照については、リンク 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)
Jenkins 2.0を使用している場合、プロパティファイル(必要なすべての環境変数と対応する値で構成されます)をロードし、そこにリストされているすべての環境変数を自動的に読み取り、Jenkinsが提供するenvエンティティにそれを注入できます。
上記のアクションを実行するメソッドを次に示します。
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)
疑問がある場合は私に聞いてください