PHPエンジニアのためのJenkins2入門

  • 8
    いいね
  • 0
    コメント

タイトルは釣り

  • あまりPHP関係なかった

Jenkins


インストール

スクリーンショット 2017-02-08 15.22.43.png

  • Weekly Release
    • 毎週リリースされる最新版
  • LTS Release
    • 12週間ごとにリリースされる安定版
    • 脆弱性とかがあるときは随時リリース

ダウンロードして java -jar

$ wget http://mirrors.jenkins-ci.org/war/latest/jenkins.war
$ java -jar jenkins.war

Dockerでrun

docker run --rm -u root \
    -p 8080:8080 -p 50000:50000 \
    -v /usr/bin/docker:/usr/local/bin/docker \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v jenkins_home:/var/jenkins_home \
    jenkins

あとはウィザードに従って


軽くデモ


Docker

  • CIとの相性が良い
    • 秘伝のタレを継ぎ足した環境ではなく、クリーンな環境でビルドできる
  • Jenkins自体の管理が楽になる
    • 秘伝のタレを継ぎ足したJenkinsサーバではなくなる
    • Jenkinsサーバが壊れたときにすぐに復旧できるか?
  • Dockerでビルドできるようにしておくと他のCIサービスにも移行できる
  • PHPは環境を作るのに手間がかかる(個人の感想です)

プラグイン

スクリーンショット 2017-02-08 15.30.27.png

  • https://plugins.jenkins.io/
  • 1300+のプラグイン (2017/02/08時点)
  • プラグインで色々なビルドをサポート
  • 今日はプラグインの話はほとんどありません

EC-CUBE

スクリーンショット 2017-02-08 16.20.33.png


今日のお話

  • ビルド・パイプライン編
  • 高機能cron編

ビルド・パイプライン編


Pipeline

  • ビルド・パイプラインをDSLで記述できる

ノード

// マスターノードで実行
node {
   echo 'Hello World'
}

// 'windows'とラベル付けされたノード上で実行
node('windows') {
   echo 'Hello Windows'
}

ステージ

node {
    stage('最初のステージ') {
        // このステージで行う処理を記述
    }
    stage('次のステージ') {
        // このステージで行う処理を記述
    }
}

スクリーンショット 2017-02-08 18.18.28.gif


スクリーンショット 2017-02-08 18.20.33.gif


/pipeline-syntax Pipeline Syntax

スクリーンショット 2017-02-08 16.33.02.png

  • パイプラインスクリプトの記述方法を教えてくれる便利機能
  • プラグインごとに記述方法が異なるのでこの機能を使ってスニペットを作成する

/pipeline-syntax/globals グローバル変数

スクリーンショット 2017-02-08 16.34.08.png

  • パイプラインスクリプトで使用できる変数一覧

/credentials 認証情報

  • パスワードや秘密鍵などを管理できる機能
  • パイプラインスクリプトにパスワード等を直書きしなくてよくなる
  • この機能で管理させることでJenkinsサーバに手動で仕込んでおく必要がなくなる
  • JENKINS_HOMEを安全にバックアップしておけば、リストア時の手間が省ける

EC-CUBEのテストをする


EC-CUBEのテストパイプライン

  • ソースのチェックアウト
  • テストに使うコンテナ準備
    • DBサーバ
    • メールサーバ
  • 前準備
    • composerによるライブラリインストール
    • EC-CUBE初期化
  • テスト実行
    • PHPUnit
  • コンテナ削除
  • レポート
    • JUnitレポートの保存
    • Slack通知

チェックアウト

stage('Git checkout') {
    git credentialsId: 'github', url: 'git@github.com:kiy0taka/ec-cube.git'
}

コンテナの準備

stage('Start containers') {
    postgres = docker.image("--name ${JOB_NAME}-${BUILD_NUMBER}-db -e TZ=Asia/Tokyo postgres:latest").run()
    mailcacher = docker.image('--name ${JOB_NAME}-${BUILD_NUMBER}-mail schickling/mailcatcher').run()
    sleep 3
}
  • docker run オプション イメージ -> docker.image(オプション イメージ).run()
  • 並列実行できるよう、コンテナに一意な名称をつける
  • Container.run() 非同期っぽいので sleep 3
  • runしたコンテナはちゃんとstopさせないといけないのでtry-finallyで囲っておく

テストの実行

docker.image('eccube/php7-ext-apache').inside("""
        -e TZ=Asia/Tokyo -e DBSERVER=db -e DBUSER=postgres -e MAIL_HOST=mail
        --link ${JOB_NAME}-${BUILD_NUMBER}-db:db --link ${JOB_NAME}-${BUILD_NUMBER}-mail:mail""") {

    stage('Composer install') {
        sh 'composer install --dev --no-interaction -o'
    }

    stage('EC-CUBE install') {
        sh 'php ./eccube_install.php pgsql none'
    }

    stage('PHPUnit Test') {
        sh 'vendor/bin/phpunit --log-junit junit.xml'
    }
}
  • docker.image('イメージ').inside('オプション') { 処理 } マジ便利
  • { 処理 }はコンテナ内で実行される
  • { 処理 }が終わるとコンテナが破棄される
  • phpunit --log-junit

コンテナを落とす

stage('Stop containers') {
    postgres.stop()
    mailcacher.stop()
}
  • finallyブロックで確実に

ビルド結果の通知

stage('Report') {
    // JUnitレポートの保存
    junit 'junit.xml'
    // Slack通知
    slackSend "${JOB_NAME} ${BUILD_NUMBER} ${currentBuild.result} (${BUILD_URL})"
}

全体像

node {

    stage('Git checkout') {
        git credentialsId: 'github', url: 'git@github.com:kiy0taka/ec-cube.git'
    }

    try {
        stage('Start containers') {
            containerPrefix = "${JOB_BASE_NAME}-${BUILD_NUMBER}"
            postgres = docker.image("--name ${containerPrefix}-db -e TZ=Asia/Tokyo postgres:latest").run()
            mailcacher = docker.image("--name ${containerPrefix}-mail schickling/mailcatcher").run()
            sleep 3            
        }

        docker.image('eccube/php7-ext-apache').inside("""
                -e TZ=Asia/Tokyo -e DBSERVER=db -e DBUSER=postgres -e MAIL_HOST=mail
                --link ${containerPrefix}-db:db --link ${containerPrefix}-mail:mail""") {

            stage('Composer install') {
                sh 'composer install --dev --no-interaction -o'
            }

            stage('EC-CUBE install') {
                sh 'php ./eccube_install.php pgsql none'
            }

            stage('PHPUnit') {
                sh 'vendor/bin/phpunit --log-junit junit.xml'
            }
        }
        currentBuild.result = 'SUCCESS'
    } catch (e) {
        currentBuild.result = 'FAILURE'
    } finally {
        stage('Stop containers') {
            postgres.stop()
            mailcacher.stop()            
        }

        stage('Report') {
            junit 'junit.xml'
            slackSend "${JOB_NAME} ${BUILD_NUMBER} ${currentBuild.result} (${BUILD_URL})"
        }
    }

}

Github Organization Folder

  • GithubのOrganizationやユーザのリポジトリをスキャンしてブランチごとにジョブを作ってくれる機能
  • リポジトリにJenkinsfileを入れておく

    stage('Git checkout') {
        git credentialsId: 'github', url: 'git@github.com:kiy0taka/ec-cube.git'
    }
    
    stage('Git checkout') {
        checkout scm
    }
    

デモ


高機能cron編


高機能cron

  • スケジューリング
  • ロギング
  • 通知
  • 手動実行
  • etc.
  • http://rundeck.org/ とかありますが

デモ DBバックアップ

  • SSHでサーバに入ってデータベースをダンプする

その他

  • デプロイ
    • git pull
  • 監視
    • curl
  • DBリストア
    • リストアできるのを確認するまでがバックアップ
  • バッチ処理
    • php app/console xxx
  • SSL証明書更新
    • Let's Encrypt

まとめ

  • パイプラインスクリプトはYAMLじゃないので複雑かも
  • スクリプトを書けるので柔軟性が高い
  • Jenkinsfileにすることでバージョン管理も可能に
  • 面倒な(個人の感想です)PHPのCI環境もJenkins+Dockerで