高度なシステム管理のためのJenkins Groovy Script Consoleをマスターする
Jenkinsは現代のCI/CDパイプラインの根幹であり、その拡張性モデルを通じて比類なき柔軟性を提供します。ほとんどの管理者はグラフィカルユーザーインターフェース(GUI)や宣言型パイプラインスクリプトに頼っていますが、Groovyで動作するJenkins Script Consoleは、即座なシステム内部調査、設定変更、そして標準的なパイプラインステップを超える高度な自動化のための直接的で低レベルなインターフェースを提供します。このコンソールは、本番環境の問題のトラブルシューティング、一括更新の実行、またはJenkinsコアシステムの直接管理を必要とするシステム管理者にとって不可欠です。
このガイドでは、Groovy Script Consoleを活用して強力な管理タスクを実行し、複雑な手動操作を効率的でスクリプト可能な操作へと変える方法を順を追って説明します。このツールをマスターすることは、標準的なパイプライン管理から真のJenkinsシステム管理へと移行するための鍵となります。
Jenkins Script Consoleを理解する
Jenkins Script Console(Jenkinsの管理 -> スクリプトコンソール)は、Jenkinsが推奨するスクリプト言語であるGroovyを使用して、実行中のJenkinsマスターのオブジェクトモデルと直接対話するためのゲートウェイを提供します。これにより、管理者はシステム設定、ジョブオブジェクト、ビルドレコード、接続されたエージェントなど、Jenkinsランタイム内のほぼすべてのオブジェクトにアクセスできます。
Script Consoleを使用する理由
- 即時実行: ジョブのトリガーやパイプラインの開始を待つことなく、スクリプトを即座に実行できます。
- システムデバッグ: GUIでは公開されていない内部状態、ログ、設定の詳細にアクセスできます。
- 一括操作: 複数のジョブの変更、エージェントの再設定、インスタンス全体の古いデータの一括消去を迅速に行うことができます。
- スクリプトのプロトタイプ作成: Groovyロジックを共有ライブラリや宣言型パイプラインに組み込む前にテストできます。
安全上の注意:直接アクセスの力
警告: コンソールで実行されるスクリプトは、Jenkinsマスター上で完全な管理者権限で動作します。不適切に書かれたスクリプトは、設定を破損させたり、ビルドを削除したり、Jenkinsインスタンスをクラッシュさせたりする可能性があります。複雑なスクリプトは、常に本番環境以外で十分にテストしてください。
必須のGroovyオブジェクトとAPIアクセス
コンソールの力は、Jenkinsのコアオブジェクトに直接アクセスできる点にあります。これらのオブジェクトは、Groovy実行環境内で暗黙的に利用可能です。
Jenkins.instance: 実行中のマスターを表す、Jenkinsのコアシングルトンオブジェクト。Hudson:Jenkinsのエイリアス。Jenkins.instance.getItemByFullName('JobName'): 特定のジョブにアクセスします。Jenkins.instance.getComputer('AgentName'): 特定のエージェント(ノード)にアクセスします。
Jenkinsインスタンスへのアクセス
アクセス権があることを確認するには、最も簡単なコマンドはJenkinsのバージョンを表示することです。
println "Jenkins Version: ${Jenkins.instance.version}"
println "Running as user: ${Jenkins.instance.getAuthentication().getName()}"
実用的な管理スクリプト
ここでは、Script Consoleを介した高度な管理制御を示す、いくつかの実用的なスクリプトを紹介します。
1. ジョブ設定の一括更新
このスクリプトは、既存のすべてのジョブを反復処理し、説明の変更や複数のプロジェクトのSCM URLの同時更新など、特定の構成要素を変更します。この例では、すべてのフリースタイルプロジェクトの説明に標準化されたサフィックスを追加します。
import hudson.model.FreeStyleProject
final String SUFFIX = " [Automated Update]"
def count = 0
Jenkins.instance.getAllItems(FreeStyleProject.class).each { job ->
if (!job.getDescription().endsWith(SUFFIX)) {
job.setDescription(job.getDescription() + SUFFIX)
job.save()
println "Updated description for: ${job.getName()}"
count++
}
}
println "\nFinished. Total jobs updated: ${count}"
2. Jenkinsエージェント(ノード)の管理
管理者は、メンテナンスのためにエージェントをオフラインにしたり、動作不良のノードを手動で切断したりする必要があることがよくあります。
エージェントを一時的に切断する
このスクリプトはエージェントを切断し、新しいビルドがその上で開始されるのを防ぎますが、実行中のビルドは完了させます。
import hudson.model.Computer
final String AGENT_NAME = "my-specific-agent"
def agent = Computer.instance.get(AGENT_NAME)
if (agent) {
// Set temporarily offline
agent.setTemporarilyOffline(true, "Maintenance started by Admin Script.")
println "Agent '${AGENT_NAME}' set to temporarily offline."
} else {
println "Agent '${AGENT_NAME}' not found."
}
エージェントを強制的にオフラインにし、実行中のタスクを切断する
エージェントを直ちに停止する必要がある場合、エージェントを強制的にオフラインにし、実行中のビルドを切断することができます。これにより、設定に応じてビルドは失敗または中止としてマークされます。
import hudson.model.Computer
final String AGENT_NAME = "unresponsive-node-01"
def agent = Computer.instance.get(AGENT_NAME)
if (agent) {
// Force offline and disconnect running tasks immediately
agent.doDoDisconnect()
println "Agent '${AGENT_NAME}' forcefully disconnected."
} else {
println "Agent '${AGENT_NAME}' not found."
}
3. 実行中のビルドを操作する
重要なビルドが停止したり、即座にキャンセルする必要がある場合、Script Consoleが最も速い方法を提供します。
特定の実行中ビルドを中止する
フルパス(例:PipelineJob/BuildNumber)で識別されるビルドを中止するには:
// Example: Aborting build #5 of the job named 'CriticalDeploy'
final String JOB_NAME = "CriticalDeploy"
final int BUILD_NUMBER = 5
def job = Jenkins.instance.getItemByFullName(JOB_NAME)
def build = job.getBuild(BUILD_NUMBER)
if (build && build.isBuilding()) {
build.doCancel()
println "Build ${JOB_NAME}#${BUILD_NUMBER} has been cancelled."
} else {
println "Build ${JOB_NAME}#${BUILD_NUMBER} is not running or does not exist."
}
4. 古いビルドレコードのクリーンアップ
ディスクスペースの管理には、古いビルドを積極的に削除する必要があることがよくあります。このスクリプトは、指定されたジョブの30日以上前のすべてのビルドを識別して削除します。
import hudson.model.Job
import java.util.concurrent.TimeUnit
final String TARGET_JOB = "LegacyArchivingJob"
final int DAYS_TO_KEEP = 30
def job = Jenkins.instance.getItemByFullName(TARGET_JOB)
if (job instanceof Job) {
long cutoffTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(DAYS_TO_KEEP)
int deletedCount = 0
job.getBuilds().each { build ->
if (build.getTimeInMillis() < cutoffTime) {
println "Deleting old build: ${build.getDisplayName()}"
build.delete()
deletedCount++
}
}
println "\nCleanup complete. Deleted ${deletedCount} builds for ${TARGET_JOB}."
} else {
println "Job '${TARGET_JOB}' not found or is not a standard Job type."
}
コンソールスクリプトのベストプラクティス
システムレベルの変更を実行する際には、安定性を維持するために以下のベストプラクティスに従ってください。
.save()の使用: 設定オブジェクト(ジョブやビューなど)を変更する際は、Jenkinsの再起動後も変更が保持されるように、そのオブジェクトに対して必ず.save()を呼び出す必要があります。設定は保存されるまでメモリにのみ保持されます。- オブジェクトの存在チェック: ジョブ名やエージェント名を誤入力した場合にコンソールがクラッシュするのを防ぐため、API呼び出しは常にチェック(
if (object)またはtry-catch)で囲んでください。 - 永続的なループを避ける: スクリプトは同期的に実行されます。コンソールUIをブロックするため、すぐに完了することが確実でない限り、長時間実行されるループやプロセスをコンソールで直接実行しないでください。
- 組み込みメソッドを活用する: Jenkins Groovyオブジェクトには、特定のヘルパーメソッド(
doCancel()やdoDoDisconnect()など)が用意されていることがよくあります。可能な限り、内部状態を手動で操作しようとする代わりに、これらのメソッドを使用してください。 - サイレントモードの使用(該当する場合): 過剰なビルドステータス更新を生成する一括操作を実行する際は、イベント通知機能を一時的に無効にすることが適切かどうかを検討してください。ただし、これは通常、標準的な管理よりも深いシステムアクセスを必要とします。
Jenkins Groovy Script Consoleをマスターすることで、単にJenkinsを使用するだけでなく、そのコアを積極的に管理し最適化できるようになります。これらのテクニックを実践することで、自動化サーバーをきめ細かく制御できるようになり、複雑なメンテナンス期間中や緊急時に対応力を劇的に向上させることができます。