GeekFactory

int128.hatenablog.com

Jenkinsfileによるジョブ管理のメリットと実例

ジョブの設定をJenkinsfileで管理し始めてから3か月ぐらい経ったので、知見をまとめてみます。

Jenkinsfileを使うメリット

Jenkinsの画面でジョブを管理していると以下のような問題が起きることが多いと思います。

  • 誰かが勝手にJenkinsの設定を変更して動かなくなった
  • ジョブ設定を別リポジトリに横展開したいけど、ポチポチ設定するのが面倒

JenkinsfileをGitで管理することで、以下のメリットがあります。

  • いつ、誰が、なぜジョブ設定を変更したのか後から調べられる
  • Pull Requestでジョブ設定の変更をレビューできる
  • ブランチを使ってジョブ設定を試行錯誤しやすい

Jenkinsの運用ポリシー

前項のメリットを実現するには、Jenkinsを以下のポリシーで運用することが望ましいでしょう。

  • Jenkinsの設定は最小限に抑える
  • なるべく画面からジョブ設定を変更せずに済むようにする(GitHub OrganizationやMultibranch Pipelineを利用)
  • なるべくJenkinsにログインしなくてもオペレーションが回るようにする(ビルド結果をチャットに通知)
  • Jenkinsfileをポータブルにする(認証情報を書かない、Jenkins Agentをイミュータブルにする等)

Jenkinsfileのテンプレート

どの言語でも共通のテンプレートを用意しておくと便利です。以下のようなテンプレートを利用しています。

node {
  try {
    checkout scm

    stage('build') {
      try {
        // TODO: ビルドを実行する
        // TODO: チャットにビルド成功を通知する
      } finally {
        // TODO: テスト結果を収集する (junit, publishHTMLなど)
      }
    }
  } catch (e) {
    // TODO: チャットにビルドエラーを通知する
    throw e
  }
}

ビルド結果はチャットの専用チャンネルに通知するようにしています。ただし、masterブランチのビルドエラーが起きた場合はすぐに直す必要があるので普段のチャンネルに流すようにしています。

  } catch (e) {
    // TODO: チャットにビルドエラーを通知する
    if (env.BRANCH_NAME == 'master') {
      // TODO: チャットにmasterが壊れたと通知する
    }
    throw e
  }

GradleでJVM言語をビルドする

GradleでJava、Groovy、Kotlinなどをビルドする場合は以下のようになります。

node {
  try {
    checkout scm
    sh 'chmod +x gradlew'

    stage('check') {
      try {
        sh './gradlew check'
      } finally {
        // TODO: テスト結果を収集する
        junit allowEmptyResults: true, testResults: 'build/test-results/test/*.xml'
        publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: false, reportDir: 'build/reports/jacoco/test/html', reportFiles: 'index.html', reportName: 'Coverage'])
        publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: false, reportDir: 'build/reports/tests/test/html', reportFiles: 'index.html', reportName: 'Test'])
      }
    }

    // TODO: チャットにビルド成功を通知する
  } catch (e) {
    // TODO: チャットにビルドエラーを通知する
    throw e
  }
}

ビルド実行時の情報を使う

ビルド実行時に取得できる情報は、JenkinsのGlobal Variable Referenceで確認できます。例えば、 env.BRANCH_NAME でブランチ名を取得できるので、masterブランチの場合にのみ特殊な処理を行うといったことも簡単にできます。

    if (env.BRANCH_NAME == 'master') {
      // masterブランチの場合はSonarQubeの静的解析を行う
      sh './gradlew sonarqube'
    }

また、パスワードやアクセストークンのような認証情報はJenkinsで管理し、ビルド実行時に注入させることができます。

withCredentials([usernamePassword(credentialsId: 'xxx', passwordVariable: 'AWS_SECRET_ACCESS_KEY', usernameVariable: 'AWS_ACCESS_KEY_ID')]) {
  // S3にリリースする
}

まとめ

本稿ではJenkinsfileでジョブ設定を管理するメリットを説明し、Jenkinsfileの実例を紹介しました。