Jenkinsパイプラインのよくあるエラーとそのトラブルシューティング
Jenkinsパイプラインの失敗に悩んでいませんか?このエキスパートガイドでは、最も一般的なエラーの実践的な解決策を詳しく解説します。Groovyの基本的な構文ミスや環境設定の誤りから、複雑なセキュリティや認証情報管理の失敗まで幅広くカバー。コンソール出力の効果的な活用方法、`withCredentials`を使ったシークレットの安全な管理、'command not found'エラーの解決方法を学び、CI/CDプロセスを安定、安全、そして信頼性の高いものにしましょう。
Jenkinsパイプラインのよくあるエラーとそのトラブルシューティング
Jenkinsパイプラインはビルドとデリバリーのステップをコード化しますが、ちょっとした構文ミスや認証情報の欠落、エージェントの違いが原因で全体の実行が中断されることがあります。最速の修正方法は、すべての赤いビルドを同じ種類の問題として扱うのではなく、失敗を階層的に読み解くことです。
まず、Jenkinsがパイプラインを解釈できなかったのか、エージェントが期待された環境を提供できなかったのか、パイプライン内のコマンド自体が失敗したのかを判断しましょう。この切り分けが調査の基盤となります。
初期診断:どこから始めるか
特定のエラーコードに飛び込む前に、トラブルシューティングの基本は効果的な診断です。常にコンテキストを収集することから始めましょう。
1. コンソール出力を分析する
コンソール出力は主要なデバッグツールです。パイプラインステップが失敗すると、Jenkinsはスタックトレース、エラーメッセージ、そして通常は実行が停止したGroovyスクリプトの特定の行を出力します。
実用的なヒント: 失敗した箇所から上にスクロールしてください。最後に成功したステップを探すことで、問題を後続のステップまたは環境の変更に絞り込むのに役立ちます。
2. パイプラインステップのリプレイ機能を使用する
軽微な構文変更がある場合や変数の問題が疑われる場合は、すぐに完全なSCMチェックアウトとビルドをトリガーしないでください。Jenkinsでは、リプレイ機能を使用して、失敗したパイプライン実行を変更して再実行できます。これは、ビルド履歴を散らかすことなく、迅速な反復と修正のテストに非常に役立ちます。
3. 環境変数を検査する
多くの問題は、実行エージェントの環境設定が正しくないことに起因します。特定のステージで利用可能な環境変数を出力して、パス、ツールのインストール状況、定義された変数を確認できます。
stage('Debug Environment') {
steps {
sh 'printenv'
// または特定の確認用:
sh 'echo "Java Home: $JAVA_HOME"'
}
}
カテゴリ1: 構文、スクリプティング、Groovyエラー
GroovyはJenkinsパイプラインを記述するためのドメイン固有言語(DSL)です。構文エラーは最も一般的な初期のハードルです。
エラー1.1: プロパティまたはメソッドが見つからない
これは通常、次のように表示されます: groovy.lang.MissingPropertyException: No such property: variableName for class...
原因: 定義されていない変数を参照している、ステップ名をスペルミスしている、または宣言型パイプラインのブロック内でスクリプト化パイプラインの機能を使用しようとしている(あるいはその逆)。
解決策:
- スペルを確認する: 変数名またはステップ名が正しくスペルされ、大文字小文字が一致していることを確認してください(Groovyは大文字小文字を区別します)。
- スコープを確認する: 変数が以前の
script {}ブロックで定義された場合、特にステージ間でデータを移動する際に、正しいスコープで定義されていることを確認してください。 - スニペットジェネレーターを使用する: 組み込みステップ(
sh、git、archiveなど)については、Jenkinsのパイプライン構文 / スニペットジェネレーターツールを使用してください。これにより、指定したステップパラメータに対して正しいGroovyコードが保証されます。
エラー1.2: 宣言型パイプラインの構文が正しくない
宣言型パイプラインは厳密な構造を必要とします。エラーは、括弧の配置ミスや予約キーワードの誤った使用が原因であることがよくあります。
例: steps { ... } を使用せずに、steps ブロックをトップレベルの stage ブロック内に直接配置する。
解決策:
- 検証する: API経由でアクセス可能なJenkins組み込みのパイプラインリンターを使用します:
JENKINS_URL/pipeline-model-converter/validate。 - 再起動チェック: 永続的で混乱を招く構文エラーの一般的な原因は、ジョブを適切にリフレッシュせずにJenkinsコントローラー上でパイプラインスクリプトを直接編集することです。デバッグしているスクリプトが実際に実行されているものであることを常に確認してください。
カテゴリ2: 環境およびツールの障害
これらのエラーは、実行エージェントにパイプラインが必要とするソフトウェアや設定がない場合に発生します。
エラー2.1: ツールが見つからない(command not found)
これは、mvn、npm、docker などのコマンドを実行する際の典型的な失敗です。
原因: ツールが実行エージェントにインストールされていないか、より頻繁には、ツールのバイナリの場所がエージェントのシステム PATH に含まれていません。
解決策:
Jenkinsツールの自動インストールを使用する: Manage Jenkins > Global Tool Configuration でツールを定義します。次に、パイプライン内で
toolディレクティブを使用してそれを参照します。これにより、正しいパスが自動的に環境に注入されます。pipeline { agent any tools { maven 'Maven 3.8.4' } stages { stage('Build') { steps { sh 'mvn clean install' } } } }エージェントラベルを確認する: パイプラインが、必要なツールが実際にインストールされているノードのラベルと一致する
agentを指定していることを確認してください。agent { label 'docker-enabled-node' }
エラー2.2: エージェント接続が拒否された、またはオフライン
パイプラインがステップを開始する前にすぐに失敗する場合、エージェントが利用できない可能性があります。
原因: Jenkinsコントローラーとエージェント間の接続(通常はJNLPまたはSSH経由)が失敗したか、エージェントが過負荷またはオフラインになっています。
解決策:
- エージェントステータスを確認する: Manage Jenkins > Nodes に移動し、影響を受けるエージェントのステータスを確認します。接続ログやエラーメッセージ(例:
java.io.EOFExceptionはネットワーク接続の喪失を示唆)を探します。 - リソースを確認する: エージェントマシンに十分なメモリとCPUリソースがあることを確認します。
カテゴリ3: セキュリティ、認証情報、および認可
認証情報エラーは、パイプラインがGitリポジトリ、Dockerレジストリ、クラウドサービスなどの外部リソースにアクセスするのを妨げます。
エラー3.1: SCMチェックアウト中にアクセスが拒否された
ソースコードのチェックアウト時にパイプラインがすぐに失敗する場合、Jenkins Gitプラグインは通常、必要な認証情報を欠いています。
原因: GitリポジトリがSSHキーまたはユーザー名/パスワードを必要としていますが、それが設定されていないか、ジョブに関連付けられていません。
解決策:
- 認証情報を設定する: 必要な認証情報(例:
Username with password、SSH Username with private key)が Manage Jenkins > Credentials に保存されていることを確認します。 - ジョブに関連付ける: 宣言型パイプラインでSCMブロックを使用する場合は、
credentialsId属性が正しく設定されていることを確認します。
エラー3.2: 保存されたシークレットへの誤ったアクセス
Jenkinsfile にシークレットをハードコードしないでください。認証情報は、withCredentials ステップを使用して安全に環境に注入する必要があります。
原因: 認証情報IDを直接環境変数として参照しようとしたり、保護されたブロックの外部でシークレットにアクセスしようとしたりする。
解決策: withCredentials ヘルパー関数を使用します。これは、保存された認証情報IDを、ブロックの期間中のみ有効な安全な環境変数にマッピングします。
stage('Deploy') {
steps {
withCredentials([usernamePassword(credentialsId: 'my-docker-registry-secret',
passwordVariable: 'DOCKER_PASSWORD',
usernameVariable: 'DOCKER_USER')]) {
sh "echo 'Logging in with user: $DOCKER_USER'"
sh "docker login -u $DOCKER_USER -p $DOCKER_PASSWORD myregistry.com"
}
}
}
セキュリティ警告:
withCredentialsで定義された変数(例:DOCKER_PASSWORD)はコンソール出力で自動的にマスクされますが、それでも使用範囲を制限する必要があります。
カテゴリ4: パイプラインのフローとリソースエラー
これらの問題は、パイプラインの進行方法や実行制限の処理に関連しています。
エラー4.1: 予期しないビルド失敗または中断
パイプラインがランダムに失敗するように見える場合、または最後のステップが FATAL: Command execution failed を報告する場合、それは多くの場合、外部要因またはリソース制限を示しています。
潜在的な原因:
- プロセスタイムアウト: ステージまたはステップが割り当てられた時間制限を超えました(
options { timeout(...) }で設定されている場合)。 - OOM(メモリ不足): エージェントのメモリが不足し、オペレーティングシステムがJenkinsワーカープロセスを強制終了しました。
- ディスク容量: ディスク容量が不足しているため、アーティファクトの保存や大規模なリポジトリのクローンができません。
解決策:
- エージェントログを確認する: エージェントマシンのシステムログ(Linuxの場合は
dmesg)でOOMキラーの警告を確認します。 - タイムアウトを設定する: ステップが本当に長時間実行される場合は、
timeout値を増やします。そうでない場合は、非効率なステップを最適化します。 - ワークスペースをクリーンアップする:
wsステップを使用するか、クリーンアップステップを追加して、ワークスペースが無制限に拡大してディスク容量を消費しないようにします。
エラー4.2: 並列ステージのデッドロックまたは不整合
parallel ステージを使用する場合、スレッド間で共有される変数やリソースが予測不可能な障害やデッドロックを引き起こす可能性があります。
ベストプラクティス: 並列ブランチ内でグローバル環境変数を変更しないでください。特定の parallel ステージ内で定義されたローカル変数を使用するか、共有リソース(特定のマシンや外部サービスなど)へのアクセスをシリアル化する必要がある場合は、lock ステッププラグインを利用します。
// lockプラグインを使用したシリアル化の例
stage('Access Shared Resource') {
steps {
lock('DatabaseMigrationLock') {
// 一度に1つのパイプラインインスタンスのみがこのステップを実行できます
sh 'run_migration_script'
}
}
}
パイプラインを安定させる習慣
プロアクティブな対策を採用することで、パイプラインの失敗頻度を大幅に減らすことができます:
- 宣言型構文を使用する: ほとんどのプロジェクトでは、宣言型パイプラインによって強制される構造は、スクリプト化パイプラインよりもスクリプトエラーが発生しにくくなります。
- 実行を分離する: 可能な限り、コンテナ化されたエージェント(Docker/Kubernetes)を使用して、ビルドごとにクリーンで再現可能な実行環境を確保し、多くのツールパスの問題を排除します。
- 環境を明示的に定義する:
environmentディレクティブを使用して、エージェントのシステムデフォルトのみに依存するのではなく、パイプライン内で重要なパスと変数を明確に設定します。 - エージェントの健全性を定期的に確認する: 専用のビルドエージェントすべてのメモリ、CPU、ディスク使用量を監視して、リソース枯渇の障害を未然に防ぎます。
エラーは赤い線よりも前にあることが多い
Jenkinsはしばしば最後に失敗したステップを赤でマークしますが、有用な手がかりは通常、その前にあります。シェルコマンドが終了コード 1 で終了するのは、20行上で依存関係のインストールが失敗したためかもしれません。デプロイメントステージが失敗するのは、前のステージが空のアーティファクトを書き込んだためかもしれません。Groovyのスタックトレースが画面を埋め尽くしても、実際の間違いは1つのスペルミスの変数である可能性があります。
失敗したパイプラインを開いたら、一番下から上に向かって、最初の予期しないメッセージを探します。私は ERROR、Exception、Permission denied、not found、No such file、401、403、timeout、そして最初のゼロ以外の終了コードを探す傾向があります。次に、その行をステージ名と比較します。目標は、1つの単純な質問に答えることです:Jenkinsがパイプラインの実行に失敗したのか、それともパイプライン内のコマンドが失敗したのか?
この区別は重要です。Jenkinsが No such DSL method と言った場合、パイプラインの構文またはプラグインの可用性をデバッグしています。mvn test がテスト失敗で終了した場合、Jenkinsはその役割を果たしており、ビルドツールがプロジェクトの問題を報告しています。両方を「Jenkinsが壊れている」と扱うと、場当たり的な修正につながります。
見た目よりも奇妙に見える宣言型パイプラインエラー
宣言型パイプラインは構造に関して厳格です。agent、environment、stages、stage、steps、post、when などのブロックは正しい場所になければなりません。括弧が1つ欠けているだけで、Jenkinsがファイル内の完全に有効な後続の行について文句を言う可能性があります。
エラーが Expected a step、Undefined section、または Multiple occurrences of the stage section に言及している場合は、Jenkinsfileを最小の壊れたブロックに減らしてください。組み込みのリンターは、完全な実行の前にモデルを検証するので便利です:
curl -X POST -F "jenkinsfile=<Jenkinsfile" \
https://jenkins.example.com/pipeline-model-converter/validate
匿名アクセスが無効になっている場合は、Jenkinsインスタンスに適した認証方法を使用してください。重要なのは正確なコマンドではなく、チェックアウト、依存関係のインストール、テストセットアップを待つ前に構文を検証することです。
よくある間違いの1つは、script ブロックなしで steps 内にスクリプト化されたGroovyを直接配置することです。宣言型パイプラインはそこに通常のステップを許可しますが、より複雑なGroovyロジックは script { ... } 内に属します:
stage('Choose target') {
steps {
script {
def target = env.BRANCH_NAME == 'main' ? 'prod' : 'dev'
echo "Deploying to ${target}"
}
}
}
エラーを消すためだけにすべてを script の中に入れないでください。宣言型パイプラインを読みやすくするためのガードレールの一部が失われます。
認証情報エラー: ID、スコープ、および使用場所を確認する
認証情報の失敗は、多くの場合、Git、Docker、クラウド、またはシェルの失敗のように見えます。パイプラインは Authentication failed、403 Forbidden、repository not found、denied: requested access to the resource is denied、またはクラウドプロバイダーのアクセスエラーを表示する場合があります。コードを変更する前に、Jenkinsfile内の認証情報IDが既存の認証情報と完全に一致していることを確認してください。
また、認証情報のスコープも確認してください。フォルダーレベルの認証情報は1つのジョブには表示されても、別のジョブには表示されない場合があります。マルチブランチジョブは、リポジトリのスキャンに1つの認証情報を使用し、Jenkinsfile内で別の認証情報を使用する場合があります。これは、ブランチの検出は機能するが、チェックアウトやデプロイメントが後で失敗するため、混乱を招く可能性があります。
シェルコマンドが必要とするシークレットには withCredentials を使用し、シークレットをログから遠ざけてください:
withCredentials([string(credentialsId: 'npm-token', variable: 'NPM_TOKEN')]) {
sh '''
set +x
npm config set //registry.npmjs.org/:_authToken "$NPM_TOKEN"
npm ci
'''
}
デバッグのためにシークレットをエコーしないでください。変数が存在することを証明する必要がある場合は、その長さまたは無害なマーカーを出力します:
test -n "$NPM_TOKEN" && echo "NPM token is present"
サンドボックスと承認エラー
Groovyサンドボックスがメソッドをブロックすると、Jenkinsは Scripts not permitted to use method... を表示するか、スクリプトを 処理中スクリプトの承認 に送る場合があります。これは通常のビルド失敗ではありません。Jenkinsは、承認されていないGroovyがコントローラーレベルのアクセスで実行されるのを防いでいます。
共有パイプラインの場合、より良い修正は、安全でないロジックを管理者が管理する信頼できる共有ライブラリに移動するか、カスタムGroovyをサポートされているパイプラインステップに置き換えることです。1つのビルドをアンブロックするためだけにランダムなメソッドを承認すると、Jenkinsfileを編集できるすべてのジョブのリスクが高まる可能性があります。
プラグインの更新後にスクリプト承認が表示された場合は、注意深く読んでください。プラグインが実装を変更し、承認が必要なメソッドを呼び出すようになった場合があります。Jenkinsfileの変更によって危険な呼び出しが導入された場合もあります。対応は異なるはずです。
パイプライン内のシェルエラー
シェルステップは、単純な理由で失敗します: 間違った作業ディレクトリ、実行可能ビットの欠落、異なるシェル、環境変数の欠落、または非対話モードで異なる動作をするコマンド。
失敗するコマンドの前に小さなチェックを追加します:
sh '''
pwd
ls -la
command -v node
node --version
./scripts/build.sh
'''
スクリプトが自分のラップトップでは動作するがJenkinsでは失敗する場合は、シバンと改行コードを確認してください。Windowsの改行コードを持つファイルは、bad interpreter のような混乱を招くメッセージで失敗する可能性があります。#!/bin/bash で始まるスクリプトは、/bin/sh しか持たないエージェントイメージでは失敗します。必要なシェルをインストールするか、実際に持っているシェル用にスクリプトを書いてください。
set -euo pipefail は注意して使用してください。これはBashスクリプトで失敗を可視化するのに役立ちますが、意図的に失敗するコマンドをテストするスクリプトを壊す可能性もあります。厳格なシェルフラグを追加した後にパイプラインが失敗し始めた場合は、設計上ゼロ以外のステータスを返す可能性のある各コマンドを検査してください。
並列パイプラインと共有状態
並列ステージは、「ランダムな」パイプラインエラーの一般的な原因です。2つのブランチが同じワークスペースパスを使用したり、同じレポートファイルを書き込んだり、同じDockerタグをプッシュしたり、同じテスト環境にデプロイしたりする可能性があります。タイミングに依存するため、障害は断続的に見えます。
各並列ブランチに独自のディレクトリを割り当てます:
parallel(
unit: {
dir('work-unit') {
sh './gradlew test'
}
},
integration: {
dir('work-integration') {
sh './gradlew integrationTest'
}
}
)
ブランチが同じ外部リソースに触れる必要がある場合は、その操作のみをロックで囲みます。本当にビルド全体をシリアル化したいのでない限り、ビルド全体をロックしないでください。
リプレイが役立つ場合と役立たない場合
リプレイは、失敗した実行に対して小さなJenkinsfileの変更をテストするのに優れています。これは修正をコミットする代わりにはなりません。リプレイで問題が証明された場合は、ソース管理でJenkinsfileを更新し、ジョブを通常どおり実行してください。
リプレイは、変更された外部状態(Dockerイメージの欠落、期限切れのトークン、削除されたブランチ、不安定なサービス)によって引き起こされる失敗にはあまり役立ちません。そのような場合、同じパイプラインを再実行しても、何も説明せずに成功する可能性があります。失敗した実行から十分な証拠(コンソールログ、ステージタイミング、エージェント名、コミットSHA、認証情報ID、外部リクエストIDなど)を、それが消える前に収集してください。