初めてのJenkins Declarative PipelineでCI/CDを構築する

ステージ、エージェント、チェックアウト、テスト、デプロイゲート、認証情報、ポストアクションを備えた初めてのJenkins Declarative Pipelineを構築します。

初めてのJenkins Declarative PipelineでCI/CDを構築する

最初のJenkins Declarative Pipelineは、実用的な質問に答えるべきです:Jenkinsはコードをチェックアウトし、ビルドし、テストし、適切なブランチが通過した場合にのみデプロイ手順を実行できるか?Jenkinsfileは、アプリと同じリポジトリ内にコードとしてそのワークフローを提供します。

宣言的構文は、予測可能な構造(pipelineagentstagesstepspost)を提供するため、良い出発点です。

Declarative Pipelineの構造を理解する

Declarative Pipelineは、アプリケーションコードと一緒にSCMリポジトリ(例:Git)に保存されるJenkinsfileというファイルでワークフロー全体を定義します。このプラクティスはPipeline as Codeとして知られています。

Declarative Pipelineのコア要素

Declarative Pipelineには、以下のトップレベルブロックが含まれている必要があります:

  1. pipeline:パイプラインの内容を定義する必須の最外ブロック。
  2. agent:パイプラインまたは特定のステージが実行される場所を指定します(例:anynone、特定のラベル)。
  3. stages:1つ以上の連続したstageブロックを含みます。
  4. stage:作業の概念的なブロックを定義します(例:Build、Test、Deploy)。
  5. stepsstage内で実行される1つ以上のコマンドまたは関数を含みます。
pipeline {
    agent any 
    environment { // オプション:環境変数を定義
        APP_VERSION = '1.0.0'
    }
    stages {
        stage('Build') {
            steps {
                // コマンドをここに記述
            }
        }
    }
    post { // オプション:パイプライン完了後に実行されるアクション
        always { 
            echo 'Pipeline finished.' 
        }
    }
}

ステップ1:Jenkinsジョブの設定

コードからパイプラインを実行するには、リポジトリからJenkinsfileを読み取るようにJenkinsジョブを設定する必要があります。

  1. Jenkinsダッシュボードに移動し、New Itemを選択します。
  2. パイプラインの名前を入力します(例:my-first-ci-pipeline)。
  3. Pipelineアイテムタイプを選択し、OKをクリックします。
  4. 設定ページで、Pipelineセクションまでスクロールします。
  5. 定義をPipeline scriptからPipeline script from SCMに変更します。
  6. SCMを選択します(例:Git)。
  7. Repository URLを入力し、必要に応じて認証情報を設定します。
  8. Script PathJenkinsfile(デフォルト)に設定されていることを確認します。

ステップ2:CI/CDのためのJenkinsfileの定義

成功したデプロイメントのために標準的なステージを統合した、シンプルなCI/CDワークフローをシミュレートする包括的なJenkinsfileを作成します。

アプリケーションのソースコード(例:シンプルなPythonまたはJavaプロジェクト)とJenkinsfileがルートにあるリポジトリ構造を想定します。

完全なDeclarative Pipelineの例

このパイプラインはnodeエージェント(設定されている場合)を使用し、基本的なシェルステップ(sh)を利用して実際の作業をシミュレートします。デプロイステージは条件付きで、前のステージが正常に完了した場合にのみ実行されます。

// Jenkinsfile
pipeline {
    // 1. エージェント定義:パイプライン全体が実行される場所を指定
    agent { 
        label 'my-build-agent' // 利用可能な特定のラベルを使用、または'any'
    }
    
    // 2. 環境変数:パイプライン全体で使用可能な変数を定義
    environment {
        CONTAINER_REGISTRY = 'registry.example.com'
        IMAGE_NAME = 'myapp'
    }
    
    stages {
        
        // ステージ1:チェックアウト(ソースコード管理)
        stage('Checkout Source') {
            steps {
                // 'checkout scm'ステップは、Jenkinsジョブ設定で定義された設定に基づいてコードを自動的にチェックアウトします。
                checkout scm
                sh 'echo "Source code successfully checked out."'
            }
        }
        
        // ステージ2:ビルド成果物
        stage('Build Artifact') {
            steps {
                sh 'echo "Starting build for $IMAGE_NAME:$BUILD_ID"'
                // シミュレーション:Dockerイメージをビルドするか、jar/warファイルをコンパイル
                sh "docker build --label build_id=${BUILD_ID} -t ${CONTAINER_REGISTRY}/${IMAGE_NAME}:${BUILD_ID} ."
            }
        }
        
        // ステージ3:テストと品質ゲート
        stage('Run Tests') {
            steps {
                sh './run_unit_tests.sh'
                sh 'echo "Running integration tests..."'
                // テスト結果を収集する例(適切なプラグインが必要)
                // junit '**/target/surefire-reports/*.xml'
            }
        }
        
        // ステージ4:デプロイ(条件付き)
        stage('Deploy to Staging') {
            // 'when'ディレクティブは、特定の条件下でのみステージが実行されるようにします
            when {
                branch 'main'
            }
            steps {
                sh "docker push ${CONTAINER_REGISTRY}/${IMAGE_NAME}:${BUILD_ID}"
                sh 'kubectl apply -f k8s/deployment-staging.yaml'
                script {
                    // Scriptブロックは、Declarativeステップ内で従来のGroovyロジックを許可します
                    echo "Deployment successful to Staging environment."
                }
            }
        }
    }
    
    // 3. ポストアクション:最終的なパイプラインステータスに基づいてアクションを定義
    post {
        success {
            echo 'Pipeline completed successfully. Notifying team via Slack...'
            // slackSend channel: '#devops-alerts', message: 'CI/CD Success!'
        }
        failure {
            echo 'Pipeline failed. Review logs for errors.'
        }
        cleanup {
            sh 'docker image prune -f --filter "label=build_id=$BUILD_ID"'
        }
    }
}

ステップ3:パイプラインの実行と監視

Jenkinsfileがコミットされ、Jenkinsジョブで設定されたブランチにプッシュされたら:

  1. Jenkinsジョブページで、Build Nowをクリックします(またはSCMポーリング/ウェブフックトリガーを待ちます)。
  2. Build Historyパネルでビルドを監視します。
  3. 実行中のビルド番号をクリックし、Console Outputを選択して実行の詳細をステップごとに表示します。
  4. Stage Viewの可視化(プラグインがインストールされている場合)を使用して、CheckoutBuildTestDeployステージの進行状況をグラフィカルに確認することもできます。

ベストプラクティスと高度な機能

ライブラリと共有コードの活用

複雑または非常に反復的なステップの場合、Jenkinsfileに冗長なGroovyを直接記述するのは避けてください。代わりに、Shared Librariesを使用します。これらの外部ライブラリを使用すると、共通の関数(標準的なデプロイ手順や通知関数など)を定義でき、複数のパイプラインから呼び出せるため、Jenkinsfileがよりクリーンになります。

// 共有ライブラリステップの呼び出し
stage('Custom Setup') {
    steps {
        customLibrary.initializeEnvironment(env: 'prod')
    }
}

認証情報の取り扱い

機密情報(パスワード、トークン、APIキー)をJenkinsfileに直接ハードコードしないでください。Jenkinsの組み込み認証情報管理システムを使用します。

withCredentialsステップを使用すると、保存されたシークレットに安全にアクセスできます:

stage('Authenticate Registry') {
    steps {
        withCredentials([usernamePassword(credentialsId: 'docker-registry-creds', 
                                          passwordVariable: 'PASS', 
                                          usernameVariable: 'USER')]) {
            sh '''
                printf '%s' "$PASS" | docker login \
                  --username "$USER" \
                  --password-stdin "$CONTAINER_REGISTRY"
            '''
        }
    }
}

エージェントの選択

ヒント: agent anyではなく、常にlabelを使用してエージェントを具体的に定義してください。agent anyを使用すると、パイプラインがJenkinsコントローラーノードで実行される可能性があり、これはセキュリティリスクとなり、コントローラーのパフォーマンスに影響を与える可能性があります。必要なツール(Docker、Maven、Node.js)がインストールされた適切に設定されたJenkinsエージェント(ノード)があることを確認してください。

まとめ

最初のパイプラインは退屈で信頼性の高いものにしましょう:実際のエージェントラベルを選択し、コードをチェックアウトし、ビルドし、テストし、ブランチでデプロイをゲートし、シークレットはJenkins認証情報に保持します。それが機能したら、成果物の公開、セキュリティスキャン、環境の昇格を一度に1ステップずつ追加してください。