こんにちは!開発現場の裏側で、日々コードとパイプラインの海を泳いでいる先輩エンジニアです。
今回は、多くの開発チームが一度は頭を悩ませる「Jenkinsのレガシーな世界からの脱却」についてお話しします。
「昔からあるGroovyスクリプト書きまくりのJenkinsfile、誰も修正したくない……」
「エラーが出てもどこでコケているのかパッと見でわからない……」
そんな絶望的な状況、ありませんか?
これを放置すると、CI/CDパイプラインは技術的負債の塊となり、デプロイのたびにチーム全体のストレスがマッハで上昇します。
今回は、古いScripted Pipeline(スクリプト型)から、モダンなDeclarative Pipeline(宣言型)へ安全かつ確実に移行するためのロードマップを、具体的なコードの書き換えパターン付きで優しく、徹底的に解説していきます。これをマスターすれば、毎日のビルド監視が劇的に楽になりますよ!
—
1. なぜ「宣言的(Declarative)」へ移行すべきなのか?
まず前提として、なぜ今のJenkinsfileを書き換える必要があるのか、その本質を整理しておきましょう。
Jenkinsには大きく分けて2つのパイプライン構文があります。
1. Scripted Pipeline(スクリプト型・レガシー)
- Groovyのフルパワーが使えるため何でもできる反面、「ただのプログラム」になりがちで、コードの可読性が最悪になりやすい。
2. Declarative Pipeline(宣言型・モダン)
- 構造が厳密に定義されており、「何をするか(What)」だけを書くスタイル。UIでの可視化、エラー検知、並列処理の記述などが圧倒的にエレガント。
宣言的構文に移行する最大のメリットは「誰が書いても同じ品質の、安全なパイプラインになること」です。文法エラーを事前に検知しやすく、JenkinsのビジュアルUI(Blue OceanやStage View)とも抜群の相性を誇ります。
—
2. 移行のための事前チェックリスト
闇雲に書き換えるのはバグの元です。以下のステップで安全に移行を進めましょう。
- [ ] 現状の把握: 動いているScripted Pipelineの全ステージを洗い出す。
- [ ] プラグインの更新: Jenkins本体および主要なプラグイン(Pipeline系など)を最新版にしておく。
- [ ] ブランチ戦略の策定: `main`や`master`に直接反映するのではなく、検証用の別ブランチ(例: `feature/migrate-jenkinsfile`)を切る。
- [ ] 並行稼働の準備: リポジトリ内に一時的に別名のファイル(例: `Jenkinsfile.declarative`)を置き、Multibranch Pipelineでテストビルドできるようにする。
—
3. 実践!書き換えマッピングパターン集
それでは、実際のコードをどう書き換えるのか、よくあるパターンを見ていきましょう。
パターンA:全体の構造と基本変数の定義
まずは骨組みの変更です。Scriptedでは自由なGroovy変数定義が乱立しがちですが、Declarativeでは`pipeline { }`ブロックの中に厳格にルールを置きます。
❌ レガシー(Scripted Pipeline)
// 自由度が高すぎて、何がどこで定義されているか追いづらい
node {
def myVersion = “1.0.0”
stage(‘Build’) {
echo “Building version ${myVersion}”
sh ‘mvn clean package’
}
}
⭕️ モダン(Declarative Pipeline)
// 構造が明確。どこに何を書くべきかが一目瞭然
pipeline {
agent any // 実行環境の指定
environment {
MY_VERSION = “1.0.0” // 環境変数はここで一元管理
}
stages {
stage(‘Build’) {
steps {
echo “Building version ${env.MY_VERSION}”
sh ‘mvn clean package’
}
}
}
}
—
パターンB:エラーハンドリングと後始末(try-catch vs post)
ビルドが失敗したときの通知や、成果物のクリーンアップ(後始末)の書き方も大きく変わります。Scriptedでは`try-catch-finally`の海に溺れがちですが、Declarativeには強力な`post`セクションが用意されています。
❌ レガシー(Scripted Pipeline)
node {
try {
stage(‘Test’) {
sh ‘npm test’
}
} catch (err) {
currentBuild.result = ‘FAILURE’
echo “Failed: ${err}”
throw err
} finally {
stage(‘Cleanup’) {
cleanWs() // ワークスペースの削除
}
}
}
⭕️ モダン(Declarative Pipeline)
pipeline {
agent any
stages {
stage(‘Test’) {
steps {
sh ‘npm test’
}
}
}
// 成功・失敗・常時実行などの条件ごとにスッキリ記述できる
post {
always {
cleanWs() // どんな結果であれ必ず実行される
}
failure {
echo “ビルドが失敗しました!担当者にメンションを送ります。”
// Slack通知などの処理をここに書く
}
}
}
この `post` セクションの導入により、コード量が減るだけでなく、「例外処理を書き忘れてワークスペースがゴミだらけになる」という事故を防げます。
—
パターンC:条件分岐とタイムアウト制御
「特定のブランチのときだけデプロイしたい」「テストが無限ループしたときに強制終了したい」という要件も、宣言的構文ならスマートに書けます。
❌ レガシー(Scripted Pipeline)
node {
stage(‘Deploy’) {
if (env.BRANCH_NAME == ‘main’) {
timeout(time: 10, unit: ‘MINUTES’) {
sh ‘./deploy.sh’
}
}
}
}
⭕️ モダン(Declarative Pipeline)
pipeline {
agent any
stages {
stage(‘Deploy’) {
// ステージ単位、あるいはステップ単位で条件やタイムアウトを制御
when {
branch ‘main’
}
options {
timeout(time: 10, unit: ‘MINUTES’)
}
steps {
sh ‘./deploy.sh’
}
}
}
}
`when` ディレクティブを使うことで、「このステージはどの条件のときに走るのか」が視覚的にも直感的にわかるようになります。
—
4. 段階的なテスト運用法:一気に本番へ入れてはいけない
移行作業で最もやってはいけないのが、「ある日突然、メインブランチのJenkinsfileを書き換えて全体 अप्लाई(適用)する」ことです。CI/CDパイプラインはチームのライフライン。止めると全員の仕事が止まります。
以下のステップで安全にテスト運用を行ってください。
1. 別名ファイルでのトライ
- リポジトリに `Jenkinsfile.v2` などの名前でDeclarative版を作成します。
2. Jenkins側でのジョブ個別作成
- JenkinsのUIから、一時的な検証用ジョブ(Pipeline job)を作成し、スクリプトパスに `Jenkinsfile.v2` を指定して手動ビルドします。
3. 挙動の比較
- 古いパイプラインと新しいパイプラインで、成果物やテスト結果に差異がないことを入念に確認します。
4. リネームと切り替え
- 動作確認ができたら、古い `Jenkinsfile` を削除(またはリネームしてバックアップ)し、`Jenkinsfile.v2` を正式な `Jenkinsfile` にリネームしてマージします。
—
おわりに:レガシーからの脱却は、チームの未来への投資
いかがでしょうか?
Scripted PipelineからDeclarative Pipelineへの移行は、最初は少し億劫に感じるかもしれません。しかし、一度モダンな書き方に移行してしまえば、コードの保守性は劇的に向上し、新しいメンバーがジョインした際もスムーズにCI/CDの仕組みを理解できるようになります。
「これをマスターすれば、毎日の作業が劇的に楽になりますよ!」
技術的負債を一つずつ解消し、快適でモダンな開発ライフを手に入れましょう。あなたのパイプラインの旅が、実りあるものになることを応援しています!