こんにちは!現場の最前線で泥臭くも優雅な自動化を追い求めている先輩エンジニアです。
日々のCI/CDパイプラインを回していると、こんな絶望感を味わったことはありませんか?
- 「うちの会社の謎の独自レガシーデプロイツール、既存のどのJenkinsプラグインとも連携できない……」
- 「シェルスクリプトで無理やりAPIを叩いてるけど、エラーハンドリングが複雑化して誰もメンテできないスパゲッティ状態になっている……」
- 「『ビルド成功時に社内チャットへ特殊なフォーマットで通知しつつ、監査ログDBにJSONを投げる』という要件のために、毎回数百行のGroovyスクリプトを書いてコピペしている……」
世の中の大抵のことは既存のプラグインで解決できます。しかし、「企業秘密の詰まった独自基盤」や「組織特有の面倒くさいワークフロー」に直面したとき、汎用ツールは無力です。
そんな時、「ないなら作ればいい。Jenkinsのコアを拡張して、俺たちの最強のステップを作ろう」と立ち上がれるのが、真のDevOpsエンジニアです。
今回は、社内独自のデプロイフローを自動化するための「Jenkinsカスタムプラグイン開発」の扉を、一緒に開いていきましょう。これをマスターすれば、パイプラインの表現力が無限大に広がり、毎日の作業が劇的に楽になりますよ!
—
1. なぜ「自作プラグイン」なのか?(シェルスクリプトの限界を超えて)
「シェルスクリプトやPipelineのGroovy(`sh`ステップ)で頑張るじゃダメなの?」という疑問が湧くはずです。
最初はそれで十分です。しかし、チームが拡大し、パイプラインが100個、1000個と増えていくと、シェルスクリプト地獄が始まります。
| 比較項目 | シェルスクリプト / Groovy直書き | カスタムプラグイン開発 |
| :— | :— | :— |
| 再利用性 | コピペの嵐。修正時は全リポジトリを修正 | 1つのJARとしてバージョン管理・一括配布 |
| 入力検証 | 実行時(実際にビルドを回さないとエラーに気づかない) | JenkinsのUI側でバリデーション可能(タイポ防止) |
| テスト容易性 | 実際にJenkinsを立ててテストする必要がある | 単体テスト(JUnit等)が書きやすい |
| 安全性 | 認証情報(Credentials)の漏洩リスクが高い | JenkinsのCredentials APIと安全に統合できる |
カスタムプラグインを作るとは、言ってみれば「Jenkinsにあなた専用の新しい命令(ステップ)を教え込むこと」です。それでは、開発環境の構築から始めましょう。
—
2. 開発環境の準備:現代のJenkinsプラグイン開発はここまでスマートだ
かつては面倒だったJenkinsプラグイン開発ですが、現在はMavenのアーティタイプ(雛形生成機能)を使うことで、数分でモダンな開発環境が手に入ります。
必要要件
- Java 11 または Java 17 (※現在のJenkinsの動作要件に合わせます)
- Apache Maven (3.8以上推奨)
魔法のコマンド:プロジェクトの雛形生成
ターミナルを開いて、以下のコマンドを実行してください(見やすいように改行していますが、実際は1行です)。
mvn -U io.jenkins.tools.mvn:maven-hpi-plugin:create
実行すると、グループIDやartifactIdを聞かれます。次のように入力してみましょう。
- `groupId`: `com.example.jenkins`
- `artifactId`: `my-company-deploy`
これだけで、`my-company-deploy`というディレクトリに、Jenkinsプラグインの標準的なプロジェクト構造が完璧に生成されます。生成されたディレクトリに移動し、早速中身を見てみましょう。
—
3. 精度高い「HelloWorld」:独自デプロイステップの実装
今回は、パイプラインから呼び出せるカスタムステップ(例:`myCompanyDeploy`)を作ります。デプロイ先の「環境名(staging / production)」と「タイムアウト時間」を受け取り、コンソールに熱いメッセージを出力するプラグインを書きましょう。
プロジェクト内の `src/main/java/com/example/jenkins/MyCompanyDeployStep.java` を開いて(なければ作成)、以下のようにコードを記述します。
ソースコード解説付き実装
package com.example.jenkins;
import hudson.Extension;
import hudson.AbortException;
import hudson.model.TaskListener;
import org.jenkinsci.plugins.workflow.steps.Step;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
import org.jenkinsci.plugins.workflow.steps.StepExecution;
import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Set;
public class MyCompanyDeployStep extends Step {
private final String environment;
private int timeoutMinutes = 30; // デフォルト値
// 1. Jenkinsfileから必須パラメータを受け取るコンストラクタ
@DataBoundConstructor
public MyCompanyDeployStep(String environment) {
this.environment = environment;
}
public String getEnvironment() {
return environment;
}
public int getTimeoutMinutes() {
return timeoutMinutes;
}
// 2. オプションパラメータの設定(@DataBoundSetterを使うことでJenkinsfileで省略可能に)
@DataBoundSetter
public void setTimeoutMinutes(int timeoutMinutes) {
this.timeoutMinutes = timeoutMinutes;
}
@Override
public StepExecution start(StepContext context) throws Exception {
return new Execution(context, environment, timeoutMinutes);
}
// 実際の処理を実行するインナークラス
public static class Execution extends SynchronousNonBlockingStepExecution
private static final long serialVersionUID = 1L;
private final transient String environment;
private final transient int timeoutMinutes;
protected Execution(@Nonnull StepContext context, String environment, int timeoutMinutes) {
super(context);
this.environment = environment;
this.timeoutMinutes = timeoutMinutes;
}
@Override
protected Void run() throws Exception {
// TaskListenerを使ってJenkinsのビルドコンソールに出力する
TaskListener listener = getContext().get(TaskListener.NEEDED_VARS);
listener.getLogger().println(“==================================================”);
listener.getLogger().println(“[INFO] 社内独自デプロイシステムへ接続中…”);
listener.getLogger().println(“[INFO] 対象環境: ” + environment);
listener.getLogger().println(“[INFO] タイムアウト設定: ” + timeoutMinutes + “分”);
listener.getLogger().println(“==================================================”);
// ここに社内APIの叩き処理や、独自のデプロイロジックをJavaで記述する!
if (“production”.equals(environment)) {
listener.getLogger().println(“[WARN] 本番環境へのデプロイを実行します。緊張感を持って臨んでください!”);
}
// 万が一失敗した場合は、AbortExceptionを投げればJenkinsのビルドを安全に失敗させられる
// throw new AbortException(“デプロイメントがタイムアウトしました。”);
listener.getLogger().println(“[SUCCESS] 独自デプロイメントが正常に完了しました!”);
return null;
}
}
// 3. Jenkinsにこのステップの存在を教えるDescriptor
@Extension
public static class DescriptorImpl extends StepDescriptor {
@Override
public Set extends Class>> getRequiredContext() {
return Collections.singleton(TaskListener.class);
}
@Override
public String getFunctionName() {
// Jenkinsfileで呼び出す際の関数名になる
return “myCompanyDeploy”;
}
@Nonnull
@Override
public String getDisplayName() {
// Jenkinsの「Pipeline Syntax(snippet generator)」に表示される説明文
return “社内独自デプロイメント実行ステップ”;
}
}
}
たったこれだけのコードで、Jenkinsに新しい独自ステップを教え込むことができます。設計思想として優れているのは、「失敗時のハンドリング(`AbortException`)」や「コンソール出力の構造化(`TaskListener`)」が、Javaの堅牢な型安全のなかで綺麗に完結している点です。
—
4. 動作確認:ローカルJenkinsでデバッグを爆速で行う
「プラグインの動作確認のために、毎回本番Jenkinsにアップロードして……」なんて非効率なことは絶対にしてはいけません。Maven HPIプラグインには、ローカルにテスト用のJenkinsインスタンスを即座に立ち上げる機能が備わっています。
ターミナルでプロジェクトのルートディレクトリに移動し、以下のコマンドを叩くだけです。
mvn hpi:run
マジックのようにビルドが走り、ローカル環境でJenkinsが立ち上がります。コンソールログの最後に次のようなURLが表示されます。
`http://localhost:8080/jenkins/`
ブラウザでアクセスし、フリースタイル・プロジェクトまたはPipelineジョブを作成してみてください。
Pipelineの記述画面にある「Snippet Generator(パイプライン構文)」を開くと……驚くべきことに、先ほど定義した `myCompanyDeploy: 社内独自デプロイメント実行ステップ` が選択肢に現れます!
以下のJenkinsfileを書いて実行してみましょう。
pipeline {
agent any
stages {
stage(‘Deploy’) {
steps {
// 自作したカスタムステップの呼び出し
myCompanyDeploy environment: ‘staging’, timeoutMinutes: 15
}
}
}
}
ビルドを実行すると、コンソール出力に先ほどの熱いメッセージが表示されるはずです。
ローカル環境でのコード変更は、一度 `mvn hpi:run` を再起動するか、デバッグ機能を使うことで即座に反映させることができます。
—
5. パッケージングと社内配布:HPIファイルの生成
ローカルでの動作確認が完璧にできたら、いよいよ社内Jenkinsサーバーに導入するためのパッケージ(`.hpi`ファイル)を作成します。
以下のコマンドを実行してください。
mvn clean package
ビルドが成功すると、`target/` ディレクトリの中に `my-company-deploy.hpi` というファイルが生成されます。
社内Jenkinsへのインストール方法
1. 社内Jenkinsの管理画面(`Jenkinsの管理` > `プラグインの管理`)を開く。
2. `高度な設定` タブを選択する。
3. `プラグインのアップロード` セクションから、生成された `my-company-deploy.hpi` をアップロードする。
4. Jenkinsを再起動する。
これで、あなたの会社専用のカスタムデプロイステップが、社内全体のJenkinsパイプラインで使えるようになります!
—
おわりに:社内開発体験(DX)の主導権を握ろう
今回は、Jenkinsカスタムプラグイン開発の「入り口」として、プロジェクトの生成からシンプルなステップの実装、ローカル検証までを駆け足で解説しました。
これをマスターすれば、面倒なシェルスクリプトのハックから解放され、堅牢で再利用性の高いCI/CDインフラをコードとして美しく構築できるようになります。
「既存のツールじゃ物足りない」「自分たちの手で最高のデプロイ体験を作りたい」――そのエンジニアリング魂こそが、組織のDXを真に加速させます。
ぜひ、あなたの会社だけのオリジナルステップを作ってみてください。毎日のデプロイメントが、少しだけ楽しくなりますよ!