くりにっき

フルスタックキュアエンジニアです

ドリコムを支える課金ライブラリを支えるJenkins

16新卒向けの勉強会でLTしたのですが、会社から許可がおりたので公開します。*1

ご査収ください。

スライド

合わせて読みたい(関連エントリ)

スライドの元ネタ

面白エントリ集

Jenkinsのslaveをitamaeで作った時の知見

弊社謹製のデータベースの水平分散ライブラリ

Rubyで静的解析やる時のお役立ちgem

fluentdでチャット連携した時のやつ

今週のgemについて

同僚のRubyKaigi2014の登壇資料

当日着ていたTシャツ

今期の嫁

本妻

*1:公開用に多少加工

Jenkinsをdebパッケージからインストールする

よく忘れるしググってもなかなか見つからないので自分用にメモ。

はじめに

apt-get install jenkins

でJenkinsをインストールすると最新版しかインストールできないのが不便なので僕はdebパッケージからインストールしています。

参考

$ apt-cache show jenkins | grep Version
Version: 1.601

Jenkinsは何回もバージョンアップしているはずなのに一番最新しかとれない。。。

debパッケージからインストールするメリット

  • Jenkinsのアップデートに失敗しても手軽に戻せる
    • warをとっておくという手もあるけど、tomcatだとwebappsにwarを置くだけではたまにデプロイされないので結局tomcat再起動する必要があり面倒*1
  • ダウンロードしたdebファイルの一覧がアップデート履歴にもなる

環境

Debian Wheezyで確認。

$ cat /etc/debian_version
7.8

方法

http://pkg.jenkins-ci.org/debian/ からインストールしたいバージョンを探す

$ cd  /path/to/backup/jenkins_deb

$ sudo wget http://pkg.jenkins-ci.org/debian/binary/jenkins_1.601_all.deb
$ sudo dpkg -i jenkins_1.601_all.deb

これだけで初回はjenkinsユーザの作成もやってくれるし、jettyの再起動までやってくれるのでお手軽

一度wgetしておくことで何かあってもすぐに切り戻せます。(直前のバージョンのdebファイルがローカルに残っているはずなので)

3〜4ヶ月くらいこの方法で運用してますが特に困ったことはないです

JENKINS_HOME とかの環境年数は /etc/default/jenkins に設定する

$ head /etc/default/jenkins
# defaults for jenkins continuous integration server

# pulled in from the init script; makes things easier.
NAME=jenkins

# location of java
#JAVA=/usr/bin/java
JAVA_HOME=/usr/lib/jvm/java-8-oracle
JAVA=$JAVA_HOME/jre/bin/java

*1:他のアプリサーバは知らん

Sebastian-badgeを作った

Sebastian-badgeとは

Jenkins pluginの埋め込みバッジをホスティングするサイトです

http://sebastian-badge.info/

f:id:sue445:20150205003444p:plain

RubyGems.org とかのバッジにインスパイアされて作りました。開発期間1週間くらい

Jenkins pluginの埋め込みバッジって?

こういうの

f:id:sue445:20150205003327p:plain

自分で作っといてなんだけど違和感なさすぎてすごい

githubのREADME.mdに手軽に貼れます

f:id:sue445:20150205003503p:plain

http://sebastian-badge.info/plugins/chatwork

技術的なこと

ソースコード

仕様

  • 1日1回*1 Jenkins Update Center をチェックして更新されたプラグインをDBに保存
  • バッジはsvgで表示
    • テキスト(xml)だけで画像生成できるのでお手軽。ImageMagicなどを使わなくていいのは嬉しい
  • svgが大量に呼ばれてもいいようにキャッシュを頑張った
    • サーバサイドはMemcache
    • クライアントサイドはETagヘッダとLast-Modifiedヘッダ

どうでもいいこと

参考書籍

カスタムドメインの設定で詰まったけどこの本のおかげでなんとかなった

名前の由来

JenkinsやHudsonが執事に由来しているので、ドキドキ!プリキュアに出てくる執事のセバスチャンから名前をとっています。

*1:0:00 UTC

*2:最後にとったのがsue445.net

Jenkins Workflow Pluginでパラメータ付で別のジョブを実行する方法

ググってもなかなか見つからなかったので自分用にメモ

ハマった

スニペットだと

build 'yourJobNameToBuild'

しか出ないのでジョブ名とパラメータを両方渡す方法が分からずにハマった。

f:id:sue445:20150118224056p:plain

やり方

こんな感じでやればいいらしい

build job: 'yourJobNameToBuild', parameters: [new hudson.model.StringParameterValue('PARAM1','123'), new hudson.model.StringParameterValue('PARAM2','345')]

参考URL

https://groups.google.com/forum/#!msg/jenkinsci-users/j8RJVhfTgJs/5b3-jmIXYDYJ

ただこれだと長すぎなのでこういうラッパメソッド作った。(hudson.modelもstatic import済っぽいので省略できた)

def strParam(name, value){
  new StringParameterValue(name, value)
}

def result = build job: 'yourJobNameToBuild', parameters: strParam('PARAM1','123'), strParam('PARAM2','345')]
echo result

CPSは普通のgroovyのスクリプトなのでメソッドを自由に定義できて便利。

build の戻り値は SUCCESS ,FAILURE のような文字列なので、if文書けばビルドの結果によって処理の分岐ができる。

Jenkins Chatwork Pluginのメンテナになった

突然ですが Jenkins Chatwork Plugin のメンテナになりました

今北産業

  • 半年くらい原因不明だったバグの原因見つけた
  • バグ修正してPR送ったらメンテナの権限委譲された
  • せっかくなのでupdate centerに最新版をリリースした

kwsk

半年くらい原因不明だったバグの原因見つけた

この前のこれです

バグ修正してPR送ったらメンテナの権限委譲された

せっかくなのでupdate centerに最新版をリリースした

f:id:sue445:20150116234140p:plain

wiki に詳しい使い方も書きました

これからもよろしくお願いします。

JenkinsのFailed to serializeに半年くらい悩まされてようやく解決した

忙しい人の1行まとめ

入れてるプラグインがtransientつけ忘れ

概要

Jenkinsのグローバル設定やジョブの設定を保存する時に高確率で「Failed to serialize」エラーが出てその度にJenkinsが激おこになる現象が発生

f:id:sue445:20150111134017j:plain

エラーの内容

javax.servlet.ServletException: java.lang.RuntimeException: Failed to serialize hudson.matrix.MatrixProject#publishers for class hudson.matrix.MatrixProject
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:796)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:876)
    at org.kohsuke.stapler.MetaClass$6.doDispatch(MetaClass.java:249)
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:746)

スタックトレース全文 https://gist.github.com/sue445/9dedd61faab63a87c880

スタックトレースが超長い上にエラーが起きるクラスも毎回変わるのでわけわかめ

一度このエラーになるとappサーバを再起動しないと直らないのでストレスもマッハ

ググっても似たような現象が見つからないしてっきりJavaとappサーバの組み合わせが悪いのかと思ってたら入れてるプラグイン( jenkins-chatwork-plugin )が原因でした。

原因

設定ファイルに保存すべきでない値(ジョブ実行時のインスタンス)をインスタンス変数として持っていたのが原因。プラグインを大幅修正するのに抵抗があったのでtransient(つけた変数をシリアライズ対象外にする)つけて回避。

修正したPR Fix: Failed to serialize by sue445 · Pull Request #8 · nanapi/jenkins-chatwork-plugin · GitHub

J( 'ー`)し「たかしへ。Gitlab Merge Request Builder Pluginを入れてみたわよ」

Gitlab Merge Request Builder PluginはGitlabのMergeRequest(以降MR)をビルドして結果をレスしてくれるJenkinsプラグインです

Travis CIとかCircle CIのGitlab + Jenkins版

以前社内で発表したことを社内Gitlabでやりたいなぁと思って探したら見つかりました

便利そうなんだけど図入りの説明がなかったので(主に社内用に)導入方法まとめています。

forkされたリポジトリからのMRは設定手順増えるので割愛。(だいたいアプリのリポジトリ内にfeatureブランチ作ってるMRやり取りすることが多いので)

1. インストール

Jenkinsの管理 -> プラグインの管理 -> 利用可能で検索

f:id:sue445:20141009224815p:plain

2. プラグイン全般の設定

Jenkinsの管理 -> システムの設定

f:id:sue445:20141009225115p:plain

説明

  • Jenkins Username, Jenkins API Token
    • MRにコメントするアカウント
      • このアカウントが実際にプロジェクトにJOINしていないとダメ
      • ボットアカウントをJOINさせる場合はGuestでOK
      • f:id:sue445:20141009224906p:plain

  • Crontab line
    • このプラグインはwebhookを受けてリアルタイムにビルドするのではなく、一定間隔でポーリングしてるっぽい*1
    • デフォルトの5分おきだとちょい長いので2分おきにした
  • Default success message, Default unstable message, Default failure message
    • ビルド終了後Gitlabに通知される時のメッセージのフォーマット
    • markdownや絵文字使えるんだけどデカイ画像を貼り付けるとフィードを圧迫するので自重した方がいいと思うw

悪い例

f:id:sue445:20141009225407p:plain

良い例

f:id:sue445:20141009225708p:plain

:broken_heart: でテストが落ちた様子を、 :green_heart: でテストが通った様子を表しています。

Jenkinsの管理 -> グローバルセキュリティの設定

マークアップ記法をSafe HTMLにする

f:id:sue445:20141009230741p:plain

公式だと「Raw HTML.」のままだったので分からずちょっとハマった

3. ジョブごとの設定(MRをビルドするためのジョブを追加)

このプラグインを使うと

  1. 既存のジョブに設定追加
  2. MRをビルドするためのジョブを追加

の2通りのやり方があるけど2でいきます。(MRをビルドするブランチは途中がレッドでも最終的にグリーンになっていればいいけど、masterやdevelopをビルドするジョブは常にグリーンになっててほしいので)

既存ジョブをコピー

f:id:sue445:20141009230924p:plain

MRビルドに不要な処理があれば削除する(ドキュメント生成やデプロイなど)

ジョブ設定

ソースコードの管理

「Branches to build」(mergeする時の元branch)を origin/${gitlabSourceBranch} にする

f:id:sue445:20141009231228p:plain

「Additional Behaviours」で 「Merge before build」を追加して

  • Name of repository: origin
  • Branch to merge to ${gitlabTargetBranch} (mergeする時のマージ対象のbranch)

にする

f:id:sue445:20141009231248p:plain

ビルド・トリガ

Gitlab Merge Requests BuilderにGitlab上のパスを追加 (Host URL以降)

f:id:sue445:20141009231414p:plain

その他

チャットに通知するメッセージにビルドしたbranch名を含めたければ $GIT_BRANCH を使う

Building a software project - Jenkins - Jenkins Wiki

注意点

  • 1つのジョブで複数のbranchをテストするため、前のビルドの影響をうけないようにする必要がある
    • 例)誰かがMRでカラム削除してると同時進行しているMRでカラムがなくてエラーになるので毎回 rake db:migrate:reset するのがいいと思う
  • 1つのジョブで順番に複数のMRをビルドするため、1つの辺りのビルド時間とMRの量が多くなると捌ききれなくなる

カーチャン J( 'ー`)し 連携

弊社のGitlabにはカーチャン J( 'ー`)し がいるので連携してみた

f:id:sue445:20141009224633p:plain

カーチャン J( 'ー`)しの由来はこちら

f:id:sue445:20141009233013p:plain

https://twitter.com/chiastolite/status/448026802099736576

カーチャン連携してみたらこんな感じ

f:id:sue445:20141009231658p:plain

1週間運用してみたけど、テストが通ってることを確認してmergeすると安心感があります。

「Build triggered.」でもカーチャンからメールが飛んでちょっとうざかったので後でOFFにしています。(最初に動作確認してしまえばいらない気がする)

Github + Jenkinsは?

GitHub Pull Request Builder Plugin があるっぽい

説明見る感じ使い方はだいたい同じ? *2

*1:本当はwebhook使いたいところだけどissueがずっと放置されてるのであまり期待していない

*2:むしろGitlab Merge Request Builder Pluginの方が真似してそう