タイトルは釣り
- あまりPHP関係なかった
Jenkins
- https://jenkins.io/
- オープンソースCIサーバ
- 高機能cron
インストール
- 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は環境を作るのに手間がかかる(個人の感想です)
プラグイン
- https://plugins.jenkins.io/
- 1300+のプラグイン (2017/02/08時点)
- プラグインで色々なビルドをサポート
- 今日はプラグインの話はほとんどありません
EC-CUBE
- http://www.ec-cube.net/
- 国産のオープンソースECサイト構築パッケージ
- EC-CUBE本体の開発はTravisCIを使っている
今日のお話
- ビルド・パイプライン編
- 高機能cron編
ビルド・パイプライン編
Pipeline
- ビルド・パイプラインをDSLで記述できる
ノード
// マスターノードで実行
node {
echo 'Hello World'
}
// 'windows'とラベル付けされたノード上で実行
node('windows') {
echo 'Hello Windows'
}
ステージ
node {
stage('最初のステージ') {
// このステージで行う処理を記述
}
stage('次のステージ') {
// このステージで行う処理を記述
}
}
/pipeline-syntax Pipeline Syntax
- パイプラインスクリプトの記述方法を教えてくれる便利機能
- プラグインごとに記述方法が異なるのでこの機能を使ってスニペットを作成する
/pipeline-syntax/globals グローバル変数
- パイプラインスクリプトで使用できる変数一覧
/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})"
}
- Slack通知はSlackプラグインを利用
全体像
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でサーバに入ってデータベースをダンプする
- パイプラインジョブではなく昔ながらのフリースタイル
- SSH Agent プラグイン使用
その他
- デプロイ
- git pull
- 監視
- curl
- DBリストア
- リストアできるのを確認するまでがバックアップ
- バッチ処理
- php app/console xxx
- SSL証明書更新
- Let's Encrypt
まとめ
- パイプラインスクリプトはYAMLじゃないので複雑かも
- スクリプトを書けるので柔軟性が高い
- Jenkinsfileにすることでバージョン管理も可能に
- 面倒な(個人の感想です)PHPのCI環境もJenkins+Dockerで