自分の誕生日である4/7に表参道.rb #10が開催ということでバースデーLTをしてきました
omotesandorb.connpass.com
例のやつ
www.amazon.co.jp
34歳になりました。もうすぐ定年ですが頑張ります ('A`)
近況
最近はプロビジョニングおじさん業やってます。
itamae, Serverspec, VagrantなどギリギリRubyやってます。
最近送ったPullRequest
Fix. Can not used iam_instance_profile options when spot_instance is enabled by sue445 · Pull Request #2 · KariusDx/vagrant-aws · GitHub
スポットインスタンス作成時にIAMロールが適用されなかったので適用されるようにした
Support multiple network ids by sue445 · Pull Request #148 · schubergphilis/vagrant-cloudstack · GitHub
CloudStackのAPI仕様上は複数network_idを渡せるはずなのにvagrantからだと複数のnetwork_idを渡せないので複数渡せるようにした
Add ssh_network_id configuration by sue445 · Pull Request #149 · schubergphilis/vagrant-cloudstack · GitHub
複数NICがある場合にeth0以外でsshしたかった
スライド版
LTで発表するためにいろいろ削ったダイジェスト版です
http://sue445.github.io/omotesandorb-10/
https://github.com/sue445/omotesandorb-10/blob/master/slides.md (スライドのソース)
完全版
スライドに書ききれなかった諸々の詳しい説明を含めた完全版です
三行まとめ
itamaeについて
レシピ(ミドルウェアのインストール手順など)をgemにしてRubygems.orgで公開することができる
Gemfile
gem "itamae-plugin-recipe-git_now"
recipe.rb
include_recipe "git_now"
git-now がインストールされる
sue445製itamaeプラグイン
暗号化したファイルを転送するプラグイン
sue445.hatenablog.com
tigをビルドするプラグイン
sue445.hatenablog.com
git-nowをビルドするプラグイン
sue445.hatenablog.com
tmuxをビルドするプラグイン
sue445.hatenablog.com
単独にするまでもない雑なレシピ集(今のところdebファイルやrpmファイルをダウンロードしてインストールするレシピだけ)
github.com
itamaeプラグインのテスト事情
https://rubygems.org/search?utf8=%E2%9C%93&query=itamae-plugin
- 47個中、テストを書いてるgemは18個 *1
bundle gem
直後の expect(Itamae::Plugin::Recipe::Hoge::VERSION).not_to be nil
しかないやつはノーカン
CIしてるgemは5個(全部自分のやつw)
- itamaeプラグインのIntegration TestのCIの知見を広めたいのが今回の主旨
CIされてることのメリット
- 複数OSテストしたい時に動作確認が楽(開発者視点)
- リポジトリのトップにTravis CIとかのバッジが貼ってあれば安心感がある(利用者視点)
- 常にビルドされているという安心感
- PR送った時にビルドの結果が出る安心感
itamaeプラグインをテストする手順
- ローカルでVagrant + VirtualBox環境構築
- 自分自身を適用するレシピと、それに対するテストを書く
- VirtualBox内でitamaeのレシピ&Serverspec実行
- CIでレシピ&Serverspec実行
今回は https://github.com/sue445/itamae-plugin-recipe-git_now で説明
からバイナリをインストール
自分自身を適用するレシピと、それに対するテストを書く
install.rb
include_recipe "git_now"
git_now_spec.rb
describe file("#{node[:git_now][:prefix]}/bin/git-now") do
it { should be_file }
it { should be_executable }
end
Serrverspec だとインフラの構成をrspecでテストすることができる
serverspec.org
Serverspecの中でitamaeのnodeを使う方法は下記を参考にしてください
qiita.com
VirtualBox内でitamaeのレシピ&Serverspec実行
itamae実行
Serverspec実行
Vagrantfile
https://github.com/sue445/itamae-plugin-recipe-git_now/blob/v0.1.1/Vagrantfile
itamaeやServerspecの実行はRakefileに集約しておくとCIに落としこむ時に楽です
https://github.com/sue445/itamae-plugin-recipe-git_now/blob/v0.1.1/Rakefile
taskを動的生成してますが rake -T
するとこんな感じ
rake itamae:centos70
rake itamae:debian8
rake spec:centos70
rake spec:debian8
Rakefile中の
HOSTS = %w(centos70 debian8)
はVagrantfileで使ってるVMに対応しています
https://github.com/sue445/itamae-plugin-recipe-git_now/blob/v0.1.1/Vagrantfile#L25-L41
- 海外の格安VPS
- 最低プランなら1時間で$0.007から使える
- 全部SSDなので速い
- ビルドする時だけインスタンスを立ち上げれば費用を抑えることができる
DigitalOceanの設定
API -> Your Tokens -> Generate New Tokenよりアクセストークンを生成
表示されたトークンは後で使うのでブラウザのタブはそのままにしておく
wercker-box-rvm-vagrant-digitalocean
https://github.com/sue445/wercker-box-rvm-vagrant-digitalocean
wercker-box-rvm-vagrant-aws をforkしてrvmとvagrantとvagrant-digitaloceanプラグインをインストール済のboxを作った
使い方
wercker.yml
box: sue445/rvm-vagrant-digitalocean@1.0.0
Werckerの設定
Classicにする
Infrastructure stackでClassicを選択 *3
ssh keyの生成
Settings -> SSH keysからDigitalOcean用の鍵を作成
Generateを押すと鍵が生成される
Environment variablesの登録
Settings -> Environment variables から環境変数を登録
- DIGITALOCEAN_ACCESS_TOKEN:さっき作ったDigitalOceanのアクセストークンを入力し、Protectedにチェックを入れる
- Protectedにチェックが入っていればビルドのコンソールにも出てこなくなる
- DIGITALOCEAN_KEY:さっき作ったsshの鍵を選択
- werckerのビルドからは
DIGITALOCEAN_KEY_PUBLIC
, DIGITALOCEAN_KEY_PRIVATE
のような変数で参照できる
wercker.yml(直列実行版)
https://github.com/sue445/itamae-plugin-recipe-git_now/blob/575ef249811ceaeba5d80ecde830c30cea46395c/wercker.yml
wercker.ymlをかいつまんで説明すると
- rvm-use:
version: 2.3.0
- script:
name: install bundler
code: gem install bundler -v 1.10.6 --no-document
- bundle-install:
jobs: 4
bundlerのバージョンが1.10.6なのは、Vagrant *4がbundler 1.11系に対応していないため
https://github.com/mitchellh/vagrant/blob/v1.8.1/vagrant.gemspec#L18
WerckerからDigitalOceanに接続するための設定
上の方で生成した秘密鍵と公開鍵を設置
- script:
name: create .ssh directory
code: mkdir -m 700 -p $HOME/.ssh
- create-file:
name: put private key
filename: $HOME/.ssh/id_rsa.vagrant
overwrite: true
hide-from-log: true
content: $DIGITALOCEAN_KEY_PRIVATE
- create-file:
name: put public key
filename: $HOME/.ssh/id_rsa.vagrant.pub
overwrite: true
hide-from-log: true
content: $DIGITALOCEAN_KEY_PUBLIC
- script:
name: chmod 600 id_rsa
code: chmod 600 $HOME/.ssh/id_rsa.vagrant
ビルド実行
- script:
name: test centos70
code: ./ci/build.sh centos70
- script:
name: test debian8
code: ./ci/build.sh debian8
centos70 -> debian8の順でビルド
build.sh
上の方でRakefileに集約したおかげでビルドスクリプトはシンプルになっています
readonly HOST=$1
vagrant up $HOST --provider=digital_ocean
bundle exec rake itamae:$HOST
bundle exec rake spec:$HOST
vagrant destroy -f $HOST
実はこれだとテストが失敗した時にVMが残り続けるという不具合がありますが後で解決します。(シェルスクリプトの中でエラーハンドリングしてもいいんだけどエラーコードを全部チェックする必要があるのでコードが冗長になる)
ビルドの並列実行
直列実行だと遅い(2つ合わせて5分くらいかかる)ので並列実行できるようにした
- Paraduct (parallel + parameterize + product)
- .travis.ymlみたいな感じにいい感じにマトリックステストをするためのgem
- 2年前に作ったgemなんだけどいろいろ書き直した
詳しい説明
sue445.hatenablog.com
sue445.hatenablog.com
上のエントリだとビルドごとにディレクトリ作ってrsyncするようになってますが、v1.0.0ではrsyncは任意になってます *5
script: |-
./ci/build.sh ${HOST}
after_script: |-
vagrant destroy -f $HOST
variables:
HOST:
- debian8
- centos70
max_threads: 4
- この例だと
./ci/build.sh debian8
と ./ci/build.sh centos70
が並列に実行される
after_script
はビルドが失敗時しても必ず実行されるので確実にVMをdestroyしてくれる
その他の特徴
capistranoみたいにホストごとに色がつくのが特徴
https://app.wercker.com/#buildstep/56f46fa951d1ad950a01ad71
CIで使う時
基本的にはビルドスクリプトで
gem install paraduct
paraduct test
みたいな処理を書くと思いますが、RubyのプロダクトであればGemfileに
gem "paraduct"
を書いて
bundle exec paraduct test
することでCIサービス側で提供されているbundlerのキャッシュ機能*6を使うことができ、ビルド時間を短縮することができます
小ネタ
- DigitalOceanのregionは当たり外れがある(気がする)
- nyc1だとたまにVM起動後にsshが通らなくて固まることがあるけど、nyc3に変えたら起こらなくなった
- ハマったら他のregionに変えてみるとよさげ
- 不慮の事故でVMが残り続けるのを防ぐために古いVMを削除するスクリプトをheroku schedulerで動かしてる
参考文献
オライリーのServerspec本にDIgitalOceanやWercker周りの説明が載ってる
www.oreilly.co.jp
itamaeやServerspecの wercker.yml
や Vagrantfile
を熟読した
付録
どうしてTravisCI じゃないのか?
こういうパラメータごとの並列ビルドだとWerckerよりも Travis CIが断然便利なのですが、あえて使わなかった理由は2つあります
DigitalOcean vs EC2スポットインスタンス
安いので有名なのはEC2のスポットインスタンスですが、同じくらいの価格帯でスペックを比較してみました *10
|
DigitalOcean ($ 0.015 / hr) |
EC2 m1.small ($ 0.01くらい) |
Memory |
1 GB |
1.7 GB |
CPU |
1 Core |
1 Core |
Disk |
30 GB |
160 GB |
公式ドキュメント
他のプランだといい感じに値段が同じくらいのがなくて1つずつしか比較できなくて申し訳ないですが、ざっと見た感じ同じくらいの値段ならスポットインスタンスの方がスペックはよかったです
難点は vagrant-awsプラグイン がスポットインスタンスに正式対応してないこと
issueには上がってる
github.com
さっきのissueで紹介されてるfork版のブランチを使う
https://github.com/mitchellh/vagrant-aws/issues/32#issuecomment-163228219
github.com
ググるとプラグインを自分でbuildしろみたいなやつが結構ヒットしますが、CIも考慮すると面倒なので自分は素直にGemfileに書いてます
source "https://rubygems.org"
group :development do
gem "vagrant", github: "mitchellh/vagrant", tag: "v1.8.1"
end
group :plugins do
gem "dotenv"
gem "vagrant-aws", github: "KariusDx/vagrant-aws", branch: "spot"
end
Gemfileに書いてるとvagrantプラグインをforkしてPullRequestする時にも自分のトピックブランチを使えるメリットもあります。(冒頭のPullRequest出してるブランチもGemfileに書いてる)
実行する時
bundle exec vagrant up --provider=aws
最後に
youtu.be
「魔法つかいプリキュア」なのにRubyスタイルでパワー強化なのはRubyistのマサカリの鋭さの現れか(考えすぎ)
重要なのでもう一度例のやつ
www.amazon.co.jp