OSS版droneで快適オンプレCI
OSS版drone をソースからビルドして自前サーバで稼働し、GitHub Enterprise (バージョン11) のprivate repogitoryでCIしました。
CentOS 6.5上に構築してます。現在のdroneはCentOS 6.xはサポート対象外という噂ですが、以下の手順でとりあえず問題なく動作します。
droneのバージョンは、2015/12/02 時点でのmasterブランチのHEADのもの使ってます。
セットアップの手順と、GH:E 11 x private repoならではのハマりどころに対するworkaroundを書きます。
droneを使った感想は、オンプレ版Travis CIみたいで控えめに言って最高といったところです。
dockerインストールと動作確認
http://qiita.com/kajitack/items/776437138630d2f4d763 通り。
sudo rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm sudo yum update sudo yum -y remove docker sudo yum -y install docker-io sudo service docker start sudo chkconfig docker on sudo docker pull centos sudo docker images centos sudo docker run -i -t centos /bin/bash # ゲストOSへ入ってみる exit
Go 1.5 のセットアップ
droneはGo製で、1.5からのvendoring使ってるので。
wget https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz tar xvf go1.5.1.linux-amd64.tar.gz mv go goroot mikdir gopath # ~/.bashrcに追記 # Go export GOROOT=$HOME/goroot export GOPATH=$HOME/gopath export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
droneのビルド
gitインストール
yum install -y git
gccのアップグレード
CentOS 6.5の gcc 4.4.7だと、droneの依存ライブラリのlibsassがコンパイルエラーになる。 http://abyssluke.hatenablog.com/entry/2014/07/07/202702 を参考にgccをアップグレード。
wget http://people.centos.org/tru/devtools-2/devtools-2.repo -O /etc/yum.repos.d/devtools-2.repo sudo yum install devtoolset-2-gcc devtoolset-2-binutils sudo yum install devtoolset-2-gcc-c++ devtoolset-2-gcc-gfortran /opt/rh/devtoolset-2/root/usr/bin/gcc --version
droneビルド
git clone git://github.com/drone/drone.git $GOPATH/src/github.com/drone/drone cd $GOPATH/src/github.com/drone/drone git log |head -n1 commit 69f5d90fd3076fe0d3db0d342e818a0800477fcd make deps # Download required dependencies scl enable devtoolset-2 bash # 新しいg++じゃないとsassのビルドに失敗する sudo ./contrib/setup-sassc.sh sudo ./contrib/setup-sqlite.sh export GO15VENDOREXPERIMENT=1 make gen # Generate code make build # Build the binary
dronercを設定してブラウザでアクセス
http://qiita.com/sonots/items/71da7797139aab7c28d1 を参考に。
https://github.dena.jp/settings/applications/new
で、CI回したい対象のレポジトリにアクセス権のあるuser/organizationでdroneアプリを登録しておく。
Application name
- drone
Homepage URL
Authorization callback URL
dronerc
を編集。 (ネットには drone.toml
での設定情報が多いが、最近は dronerc
に移行中らしい)
vim /etc/drone/dronerc #!/bin/bash # server configuration SERVER_ADDR=":80" #SERVER_CERT="" #SERVER_KEY="" # database configuration DATABASE_DRIVER="sqlite3" DATABASE_CONFIG="/var/lib/drone/drone.sqlite" # remote configuration REMOTE_DRIVER="github" REMOTE_CONFIG="https://github.dena.jp?client_id=xxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&private_mode=true&open=true&ssh=true" ## private_mode=true : private repo を扱う ## ssh=true : `git fetch` するときに、private repoのhttpsだとUsernameやPassword入力を求められてしまうので、それを回避 # docker configuration DOCKER_HOST="unix:///var/run/docker.sock" #DOCKER_CERT="" #DOCKER_KEY="" #DOCKER_CA="" # plugin configuration PLUGIN_FILTER="plugins/*"
droneを立ち上げてみる。
sudo $GOPATH/src/github.com/drone/drone/drone --config=/etc/drone/dronerc
localhostから http://DRONE_HOST:80
へアクセスし、ログインしてOAuthも突破。
注意: REMOTE_CONFIG
の ssh=true
は、GH:E 11を使用しているなら本質的に重要です。GH:E 11 だと、初回起動より前にこのオプションをつけていなければ git fetch
に失敗してテストが進行しません。もしも先に起動してしまったら、 /var/lib/drone/drone.sqlite
を一度消しましょう。
droneをデーモンとして動かす
sudo vim /etc/init.d/drone #!/bin/bash # # chkconfig: 2345 85 15 # description: drone - a CI service. ## http://qiita.com/volanja/items/383fcd6d2d2e14792723 を見て書いた . /etc/rc.d/init.d/functions prog="drone" APP_ROOT=$HOME/gopath/src/github.com/drone/drone APP_USER="root" conf=/etc/drone/dronerc lockfile="/var/lock/subsys/${prog}" logfile="/var/log/${prog}.log" CMD="${APP_ROOT}/drone --config=${conf} &" action="$1" RETVAL=0 cd ${APP_ROOT} || exit 1 start(){ echo -n $"Starting $prog: " daemon --user=${APP_USER} "cd ${APP_ROOT} && ${CMD}" > $logfile 2>&1 RETVAL=$? [ $RETVAL -eq 0 ] && touch $lockfile echo } stop(){ echo -n $"Stopping $prog: " killproc ${prog} RETVAL=$? if [ $RETVAL = 0 ]; then rm -f ${lockfile} success $"$prog stop" else failure $"$prog stop" fi echo } rh_status() { status ${prog} } case $action in start) start ;; stop) stop ;; status) rh_status ;; restart) stop sleep 2 start ;; *) echo >&2 "Usage: $0 <start|stop|restart|status>" exit 1 ;; esac exit 0
sudo chkconfig --add drone
あとは...
普通にレポジトリを有効化して、レポジトリに .drone.yml
を追加して、ブランチpushすればテストが走る。
travisみたいな感じ。
おまけ: .drone.yml の例
C++製のライブラリと、そのGoバインディングのテストを走らす設定。
build: image: drone/golang:1.5 commands: # https://github.com/google/googletest を引っ張ってくる - git submodule init - git submodule update # drone/golang:1.5 は割とミニマムなので、インクルードヘッダの入ったパッケージを取得可能にする - echo 'deb-src http://httpredir.debian.org/debian jessie main' >> /etc/apt/sources.list - apt-get update - apt-get install zlib1g-dev - wget -q https://cmake.org/files/v3.3/cmake-3.3.0-Linux-x86_64.tar.gz - tar xf cmake-3.3.0-Linux-x86_64.tar.gz - cmake-3.3.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Debug . - make -j4 VERBOSE=1 mytest - ./test/mytest - go test -x -v
git commit時の名前とemail切替をalias登録しておくと捗る
小ネタ
↑恥ずかしいアレ↑
- 会社のGitHub Enterprise用のユーザ情報が
~/.gitconfig
に書かれている - プライベートで書いたコード github.com に上げようとしたけど
git commit
時に会社ユーザ情報使われた git config --local user.name 'プライベートユーザ名'
などすれば良いんだけど、面倒でついつい忘れちゃう
そんなあなた(私)のために、
$ git laysakura # プライベート用ユーザ情報へ切替 $ git kaisha # 会社用ユーザ情報へ切替
とできるようにした話。
~/.gitconfig
... [alias] laysakura = !git config --replace-all --local user.name 'Sho Nakatani' && git config --replace-all --local user.email 'laysakura@example.com' kaisha = !git config --replace-all --local user.name 'nakatani.sho' && git config --replace-all --local user.email 'nakatani.sho@heisha.co.jp' ...
git commit
とかの普通のサブコマンドに補完が聞くなら git laysakura
とか git kaisha
にも補完効くはずで、ユーザ情報切替が捗ります
速いしスケールする並列CSVパーサ作った紆余曲折話
laysakura/PartialCsvParser · GitHub
年の瀬にどうしてもCSVを並列にパースしたくなって、PartialCsvParserというC++のライブラリを作った。
という3拍子揃ったやつです。
細かいことはプロジェクトのページを見ていただくとして、ブログには頑張ってベンチマークとった話と、全然スケールしなかったのに2行追加しただけでグンと並列性能が上がった話を書く。
作る前の勝算
CSVの並列パーサライブラリって、ちゃんとスケールするものが割と簡単に作れると思って作り始めた。
例えば2並列にしたいなら、CSVファイルを前半と後半に2分割してあげて、それぞれのスレッドで別々にパースしてあげれば良いだけ。
なぜスケールさせられると思ったかというと、
という感じ。
最初からHDDでの並列性能は無視して、SSDで戦おうと思ってた。
作ったらスケールしなかった
バージョン 0.1.0 を作ってみてSSD環境でベンチマークを取ってみたら全然スケールしなかった。寝た。
起きて悔しくなったのでもう一度色々測定してみると、 CSVファイルがページキャッシュに乗っている時、つまりオンメモリな処理をしているときは割とちゃんとスケールすることが分かった。
となるとやっぱりSSDアクセスがボトルネックになっていそう。 少し頭を巡らせパーサの気持ちになって考えてみた。
そもそもPartialCsvParserは、パース対象のCSVファイルをどかんと丸ごとmmap(2)
している。
で、複数のスレッドが同じタイミングで離れた領域(ページ)を触りに行く。
このとき、基本的には要求したページがまだメモリに乗っていなくてページフォルトを起こし、ディスクまで取りに行くことになるのだけど、複数のスレッドから同タイミングで「そこそこ離れているけどそんなに離れてはいない」ページを取りに行くことになる。
SSDの気持ちになるとこれはつらい。そもそもSSDが並列性能出るのって、SSDはフラッシュメモリ(板)の集合であって、別々の板のページを同時に要求されたら同時に返せるからってのが基本...なはず。
(SSDチップにもよるけど、)CSVファイルなんてものはサイズもたかが知れているし、同一の板にちょい離れたページを同タイミングで要求しているような気がして、そうするとSSDアクセスがボトルネックになっても仕方がないなという気持ちになった。
じゃあどうしたか
やっぱり複数スレッドから同時にCSVなんて小さいファイルにアクセスしに行くのは大変だろうと思ったので、CSVファイルをドカンと1スレッドでメモリに乗せたくなった。
1スレッドでドカンとやると、ランダムアクセスじゃなくてシーケンシャルアクセスになる。 いくらランダムアクセスに強いと言われるSSDといえど、シーケンシャルアクセスのほうが1桁は速い。
とはいえmmap(2)
を捨ててread(2)
使うのは、コーディング上面倒くさい。とても面倒くさい。
mmap(2)
でシーケンシャルに読みたい、つまりプリフェッチできないもんかなぁ。
と思って探したらmadvise(2)
が見つかった。
madvise(2)
はカーネルに「この領域はプリフェッチしておいてほしいなぁ(チラッチラッ」となんとなーくお願いするためのシステムコール、らしい。
ダメ元で使ってみたプルリクエストがこちら。
たった2行。コメント入れても3行。
これがうまくいって、グンとスケールするようになった。
結局のところ、まだスレッド作ってない段階でガツッとシーケンシャルアクセスしてメモリに乗せるので、 図らずもHDDでもちゃんとスケールするようになった。
ベンチマークを頑張ってとった話
年末で実家にこもれたので、まとまった時間とってそこそこしっかりベンチマークをとれた。
どんな風にベンチマークとったかなどは、ここ にかなりしっかり書いた(つもり)。
ここではすぐに役立ちそうなことを2点ほど。
Google SpreadSheetはデータ集計に超便利
学生時代はExcelとかGnuplot (ウッアタマガ) とか使ってベンチマーク結果を集計してたけど、会社でGoogle Drive使うこと増えてきたし、 試しにGoogle SpreadSheetでデータ集計してみた。
これが大当たりで、
- 実験結果の集計に使うレベルならExcelと遜色なく使える
- グラフウィザードがExcelよりなんとなく分かりやすい気がするし、デフォルトのデザインも悪くない
- 生データやグラフを簡単に公開できる。特にグラフは自動で画像ファイルにしてくれたりする
と最高だった。
ディスクのパフォーマンス計測にはfioがよかった
hdparm
とかbonnie++
とか、世の中には色々とディスクのベンチマークをとるためのツールが存在している。
そんな中でfioはダントツで使いやすかった。 こんな感じで、短い設定ファイル作ってコマンドライン引数にそれだけ渡せば何かそれっぽい結果が出てくる。
$ vim random-read-mem.fio [random-read] rw=randread size=512m directory=/dev/shm $ vim sequential-read-hdd.fio [sequential-read] rw=read size=512m directory=/dev/shm $ fio random-read-mem.fio
root権限いらないのもポイント高い。
まとめ
2014年も終わろうとしてるのにCSVなんて使う人少ないでしょうけど、どうしてもCSVをパースしたくなったらPartialCsvParserのことを思い出してください。
MySQLiteストレージエンジンの発表をしました
第2回 MariaDB/MySQL コミュニティ イベントで、以前作っていたMySQLiteというMySQL/MariaDBのストレージエンジンの発表をしました。
スライドはこちらです。
MySQLite: SQLiteデータベースを読み書きするMySQLストレージエンジン
他の方の発表も楽しめました。 懇親会でMariaDB開発・セールスのおじさま方に「You look so cool!」って言われたのが一番嬉しかったです。
お話を持ちかけてくれたり会場を提供してくださったDeNA様、ありがとうございました。