2026年9月17日

2026年9月17日

JenkinsのPipelineスクリプトの書き方(Jenkinsfileの基本構文と実例)

Jenkins の Pipeline は、ビルド・テスト・デプロイの手順を Jenkinsfile というテキストファイルに書き、リポジトリで一緒に管理する仕組みです。結論から言うと、これから書くなら **Declarative Pipeline(宣言型)を基本にし、複雑な分岐だけ script ブロックで補う** のが扱いやすい方法です。この記事では、基本構文、PHP/WordPress 案件を想定した実例、認証情報の安全な渡し方、書いたスクリプトの検証方法までを順に説明します。

Declarative と Scripted の違い

Pipeline の書き方には2種類あります。

  • Declarative Pipeline: pipeline { ... } で始まり、agent・stages・post などの決まったブロックに沿って書く形式。構文チェックが効きやすく、Blue Ocean や Stage View での表示も整います。
  • Scripted Pipeline: node { ... } で始まり、Groovy のコードとして自由に書く形式。柔軟ですが、書き手によって構造がばらつき、レビューしにくくなりがちです。

チームで長く運用するなら Declarative を選び、ループや動的な分岐が必要な箇所だけ script { } の中に Groovy を書く、という分担が無難です。以降の例も Declarative を中心にしています。

Jenkinsfile の最小構成

まずは骨格を押さえます。pipeline の中に「どこで動かすか(agent)」と「何をするか(stages)」を書くのが最低限です。

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'ビルドを開始します'
                sh 'php -v'
            }
        }
    }
}

agent any は「空いているどのノードでも実行してよい」という意味です。ビルド用ノードを分けている場合は agent { label 'php' } のようにラベルで指定します。Docker Pipeline プラグインを入れていれば agent { docker { image 'composer:2' } } のようにコンテナ内で実行することもできます。

sh は Linux/macOS ノード用のステップで、Windows ノードでは bat や powershell を使います。ノードの OS とステップが合っていないと「コマンドが見つからない」系のエラーになるので、最初につまずきやすい点です。

PHP / WordPress 案件を想定した実例

テーマやプラグインのリポジトリで、Composer で依存を入れ、PHP_CodeSniffer と PHPUnit を回し、main ブランチだけデプロイする例です。

pipeline {
    agent { label 'php' }

    options {
        timeout(time: 30, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '20'))
        disableConcurrentBuilds()
    }

    environment {
        COMPOSER_NO_INTERACTION = '1'
    }

    stages {
        stage('Install') {
            steps {
                sh 'composer install --no-progress --prefer-dist'
            }
        }

        stage('Checks') {
            parallel {
                stage('PHPCS') {
                    steps {
                        sh 'vendor/bin/phpcs --standard=phpcs.xml.dist'
                    }
                }
                stage('PHPUnit') {
                    steps {
                        sh 'vendor/bin/phpunit --log-junit build/junit.xml'
                    }
                }
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sshagent(credentials: ['deploy-ssh-key']) {
                    sh './scripts/deploy.sh'
                }
            }
        }
    }

    post {
        always {
            junit allowEmptyResults: true, testResults: 'build/junit.xml'
        }
        failure {
            echo 'ビルドが失敗しました。コンソール出力を確認してください'
        }
    }
}

各ブロックの役割と注意点は次のとおりです。

  • options: timeout はハングしたビルドを打ち切る設定です。外部 API を叩くテストや composer install が止まったままエージェントを占有するのを防げます。buildDiscarder は古いビルド履歴を自動で消し、ディスクの圧迫を防ぎます。disableConcurrentBuilds は同じジョブの同時実行を止め、デプロイの競合を避けます。
  • environment: ステージ全体で使う環境変数を定義します。秘密情報はここに直接書かず、後述の Credentials を使います。
  • parallel: 互いに依存しないチェックを並列に流し、待ち時間を短くします。どちらかが失敗すると全体が失敗になります。
  • when { branch 'main' }: ブランチ条件は Multibranch Pipeline のジョブで評価されるものです。通常の Pipeline ジョブでは期待どおりに判定されないことがあるので、ジョブの種類を確認してください。
  • post: 成否にかかわらず実行したい処理(テスト結果の集計、通知など)を書きます。always・success・failure・unstable などの条件が使えます。

sshagent は SSH Agent プラグイン、junit は JUnit プラグイン、parallel などの Declarative 構文自体は Pipeline 系プラグインが提供します。プラグインが入っていないステップは「No such DSL method」というエラーになるので、エラー文に出たステップ名から必要なプラグインを探すのが近道です。

認証情報(Credentials)を安全に渡す

API トークンやデプロイ用の SSH 鍵は、Jenkins の Credentials に登録し、ID で参照します。Jenkinsfile はリポジトリに入るので、値そのものを書くのは避けてください。

stage('Notify') {
    steps {
        withCredentials([string(credentialsId: 'slack-webhook-url', variable: 'WEBHOOK_URL')]) {
            sh '''
                curl -fsS -X POST -H 'Content-Type: application/json' \
                  -d '{"text":"build finished"}' "$WEBHOOK_URL"
            '''
        }
    }
}

ここで大事なのは **sh の引数をシングルクォートで囲む** ことです。ダブルクォートで "${WEBHOOK_URL}" と書くと、Groovy 側で文字列が展開されてからシェルに渡るため、値がプロセス一覧などに残るおそれがあります。最近の Jenkins はこの書き方を検出すると警告を出します。シングルクォートなら展開はシェルの環境変数として行われ、ログ上の値もマスクされます。

withCredentials は Credentials Binding プラグインの機能で、ユーザー名とパスワードの組なら usernamePassword(credentialsId: '...', usernameVariable: 'API_USER', passwordVariable: 'API_PASS') を使います。マスクはあくまで補助なので、set -x で値を表示したり、ファイルに書き出したりしないよう注意してください。

条件分岐やループは script ブロックで

Declarative の中で Groovy のロジックが必要になったら script { } を使います。

stage('Deploy targets') {
    steps {
        script {
            def targets = ['staging']
            if (env.BRANCH_NAME == 'main') {
                targets << 'production'
            }
            for (t in targets) {
                sh "./scripts/deploy.sh ${t}"
            }
        }
    }
}

この例では t は秘密情報ではない固定値なので、ダブルクォートで展開しても問題ありません。秘密情報かどうかでクォートを使い分ける、と覚えておくと安全です。

script ブロックの Groovy はサンドボックスで実行され、許可されていないメソッドを呼ぶと「Scripts not permitted to use method ...」というエラーになります。管理画面の In-process Script Approval で承認できますが、内容を理解せずに承認すると任意コード実行の入口になり得ます。多くの場合は readJSON(Pipeline Utility Steps プラグイン)のような既存のステップで置き換えられるので、まずはそちらを検討してください。

Scripted Pipeline で書く場合

参考として、同じ考え方を Scripted で書くと次のようになります。

node('php') {
    stage('Checkout') {
        checkout scm
    }
    stage('Test') {
        try {
            sh 'composer install --no-progress'
            sh 'vendor/bin/phpunit --log-junit build/junit.xml'
        } finally {
            junit allowEmptyResults: true, testResults: 'build/junit.xml'
        }
    }
}

post の代わりに try/finally で後処理を書く必要があり、timeout なども自分でラップすることになります。既存のジョブが Scripted で書かれている場合を除き、新規に書くなら Declarative の方が保守しやすいはずです。

書いたスクリプトを検証する方法

Jenkinsfile はコミットして実行するまで間違いに気づきにくいので、次の手段を組み合わせます。

  1. Pipeline Syntax(スニペットジェネレーター): ジョブ画面から開ける補助ツールで、ステップの引数をフォームで選ぶとコード片を生成してくれます。プラグインごとの正しい引数名を確認するのに便利です。画面上の表記はバージョンによって変わることがあります。
  2. Replay: 実行済みビルドの Jenkinsfile をその場で書き換えて再実行できる機能です。コミットせずに小さな修正を試せますが、確定した内容はリポジトリに反映してください。
  3. Declarative Linter: Jenkins の CLI や HTTP エンドポイントに Jenkinsfile を送ると、Declarative の構文チェックだけを行えます。エンドポイントや認証方式は環境によって異なるので、お使いの Jenkins のドキュメントを確認してください。
# Jenkins CLI(SSH 経由)で構文チェックする例。ホスト名・ポート・ユーザーは環境に合わせて変更
ssh -p 2222 your-user@jenkins.example.com declarative-linter < Jenkinsfile

構文は正しくても、ノードに composer が入っていない、作業ディレクトリが想定と違う、といった実行時の問題は残ります。最初は sh 'pwd && ls -la' のような確認用ステップを入れてログを読み、環境を把握してから本処理を書くと遠回りになりません。

よくあるつまずき

  • **when { branch } が効かない**: 通常の Pipeline ジョブで使っている可能性があります。Multibranch Pipeline にするか、env.GIT_BRANCH などを expression で判定します。
  • ワークスペースに前回の成果物が残る: Workspace Cleanup プラグインの cleanWs() を post { always { ... } } で呼ぶと、ビルドごとに作業領域を掃除できます。
  • デプロイが途中で止まった: 本番デプロイのステージ前に input ステップで承認を挟む、デプロイスクリプト側でバックアップを取ってから反映する、といった安全策を入れておくと復旧が楽になります。

Jenkins 本体と各プラグインは更新が頻繁で、ステップの引数や管理画面の表記は変わることがあります(2026年10月現在)。新しい書き方を採用する前に、公式の Pipeline Syntax リファレンスとプラグインのページで現在の仕様を確かめてください。

まとめ

  • 新規に書くなら Declarative Pipeline を基本にし、複雑なロジックだけ script ブロックに閉じ込める。
  • options でタイムアウトと履歴の上限を決め、post で後処理と通知を書く。
  • 秘密情報は Credentials に登録し、withCredentials とシングルクォートの sh で渡す。
  • スニペットジェネレーター・Replay・Declarative Linter で、コミット前に構文と引数を確かめる。
  • 本番デプロイの前には承認ステップやバックアップを入れ、まずステージング環境で動作を確認する。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲