Docker + Itamae でレシピ作成の試行錯誤を 高速化 #itamae #docker


Docker + Itamae でレシピ作成の試行錯誤を 高速化 #itamae #docker

概要

Docker + Itamae でレシピ作成の試行錯誤を 高速化 します

目的

  • Itamae のレシピ作成時間を短縮
    • 特に工夫をしないと、レシピのプロビジョニングリトライは非常に時間がかかる
      • 例えば、Ubuntu 環境に rbenv + ruby(2.1.3) + rails(4.1.8) 環境をインストールしたところ 15 分かかりました 何も工夫をしなければ再試行に + 15 分かかります
    • 普段のプログラミング同様、何事も一発で成功することは少ない。試行錯誤は発生する

※ Itamae に限った話ではないので、プロビジョニングツール全般に応用可能

前提

  • Vagrant で構築した CoreOS 環境 の上に Docker で作成した Ubuntu 14.04 のコンテナを作成し、その環境を利用します 1
  • Docker の基本操作の知識が必要です 2
  • Immutable なレシピ(冪等性を気にしない)

試行

要件

  • OS: Ubuntu 14.04
  • rbenv + ruby 2.1.3
  • rails 4.1.8
  • WebServer: WEBric
  • DB: sqlite
  • Todo アプリケーションを scaffold して rails 起動

手順

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              trusty              04c5d3b7b065        8 days ago          192.7 MB
  • 作成した Ubuntu 14.04 コンテナを確認
$ docker ps
CONTAINER ID        IMAGE                  COMMAND               CREATED             STATUS              PORTS                                        NAMES
0e50ba901b58        sample/ubuntu:trusty   "/usr/sbin/sshd -D"   4 seconds ago       Up 3 seconds        0.0.0.0:80->3000/tcp, 0.0.0.0:2222->22/tcp   berserk_ardinghelli
sudo docker run -d -p 2222:22 -p 80:3000 sample/ubuntu:trusty /usr/sbin/sshd -D
  • Rails 環境の構築まで成功したら、 Docker の commit を実行してイメージを作成します
$ docker commit <container name | id> rails_sample
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
rails_sample        latest              777715acc917        26 seconds ago      546.9 MB
sample/ubuntu       trusty              544a982d72bf        51 minutes ago      255.3 MB
ubuntu              trusty              04c5d3b7b065        8 days ago          192.7 MB
  • コンテナを停止・削除して、 commit した新規イメージでコンテナを再作成します
$ docker stop <container name | id>
$ docker rm <container name | id>
$ sudo docker run -d -p 2222:22 -p 80:3000 rails_sample /usr/sbin/sshd -D
$ docker ps
CONTAINER ID        IMAGE                 COMMAND               CREATED             STATUS              PORTS                                        NAMES
3d013b1fe510        rails_sample:latest   "/usr/sbin/sshd -D"   4 seconds ago       Up 3 seconds        0.0.0.0:80->3000/tcp, 0.0.0.0:2222->22/tcp   elegant_colden
  • rails 環境構築用のレシピに Todo アプリケーションを scaffold して、 Rails を起動するまでの記述を追加します

変更前レシピ

execute 'apt-get update' do
  command 'apt-get update -y'
end

package "build-essential" do
  action :install
end

include_recipe 'rtn_rbenv::user'

変更後レシピ

recipe.rb
execute 'apt-get update' do
  command 'apt-get update -y'
end

package "build-essential" do
  action :install
end

include_recipe 'rtn_rbenv::user'
# rails setup の include を追加
include_recipe './rails_setup.rb'
rails_setup.rb
package "libsqlite3-dev" do
  action :install
end

execute "setup rails" do
  cwd "/home/core"
  user "core"
  command <<-EOS
. /home/core/.bash_profile
rbenv rehash
rails new todo --skip-bundle
cd todo
cat << EOT >> Gemfile
gem 'execjs'
gem 'therubyracer'
EOT
bundle install
rails generate scaffold Tudu name:string estimate:integer results:integer complete:boolean
bundle exec rake db:migrate
bundle exec rails server -d
  EOS
end

※ model 名 todo は rails に予約されているので、 tudu にしています

  • itamae 実行
$ bundle exec itamae ssh -p 2222 -j node.json -i /path/to/your/key/key_name -h 172.17.8.101 -u core rails_setup.rb
  • 起動確認

データを2件登録してみました

実行時間の比較 ( + => ) ( + => )

+ =>

  • 途中で Docker のイメージを作成せずに、 itamae のレシピを全て再実行した場合
(15 分 × 2) + 2 分 = 32 分

+ =>

  • 途中で Docker のイメージを作成した場合(今回紹介した手順)
15 分 + 2 分 + N 分 = 17 + N 分

N 分 は新規イメージの作成にかかる時間。
今回の例だと docker commit の実行は 10 秒程度で終わりました。
その他オペレーション込みで 1 分程度。

たった 1 回の試行でここまで差がつくので、
試行回数が多ければもっと大きな差がつくでしょう。
普段のプログラミングと同様、レシピの作成が一発で成功する方が少ないと思うのですが、
皆さんいかがでしょうか?

効率的にレシピを作成するノウハウを余り見かけないので、今回の記事を作成しました。
私は基本的に(リアルワールドで)誰とも情報交換していないこともあり、情報弱者の可能性は高く、
今回紹介した方法より優れた方法はたくさんあるかもしれません。
この記事への突込みが入って、より優れた方法を引き出すきっかけになれば、
それはそれでいいかな、と思います。

作業フロー

  1. レシピ内の最小ステップ 3 をインクリメンタルに作成
    1. dry-run
      1. 成功
        1. 次のステップへ
      2. 失敗
        1. レシピ修正
    2. プロビジョニング実行
      1. 成功
        1. コンテナをイメージ化
        2. 新規イメージで新規コンテナ作成
      2. 失敗
        1. レシピ修正
        2. プロビジョニングに失敗したらイメージからコンテナを再作成してリトライ
  2. 新規コンテナで作業再開
  3. 全てのレシピが完成するまで 1-2 を繰り返す
  4. レシピ全体を通して実行
  5. レシピが完成したら作業用のイメージ、コンテナを破棄

補足

  • Vagrant + sahara などでもスナップショットを活用して作業用の中間イメージを作成できるが、 docker ほど早くない。
    vagrant + sahara のみを使っていて、 Docker を利用したことがない方は是非試してみてください。

  • レシピ試行の際の1回あたりの実行時間が長いと、単純に時間がかかるという以外に下記の弊害がある

    • 思考が途切れる
    • 眠くなる

試行錯誤を繰り返すたびに、作業のパフォーマンスが下がっていく。

戯れ言

  • Docker を利用した記事で Rocket ( ) のアイコンを使うブラックジョーク 4

外部資料

脚注