DevOpsDay Tokyo 2013 で GitHub の中の人 が boxen について話していて 、そそられたので試してみたメモです。

まえおき

Boxen というには何かと簡単にいうと、Mac の環境を自動構築するためのツール(フレームワーク)です。GitHub ではローカルの Mac を開発環境として使っているので、新しく人が加わった時に Boxen で開発環境構築してもらっているとのこと。

自分は今まで dotfiles はすぐに復元できるようにはしていたんですが、アプリのインストールなどは Evernote に入れてるメモを参照しながら手動でやっていたので Boxen で構築してみようかな、と思った次第です。dotfiles を github にあげている人は多いと思いますが、これからは our-boxen もあげる時代なんですかねー。

なお、boxen は puppet ベースで作られているので、設定ファイルもぶっちゃけ puppet の manifest です。puppet わかってる人には取っ付きやすそうな雰囲気。

0. 事前準備

Xcode だけは手動で入れておかないといけないようなので入れておきます。ライセンス確認があるからですかね。

あと、GitHubアカウントを作っておくと良いです。GitHub で dotfiles も管理していると尚良し。

1. ひな形のコピー

https://github.com/boxen/our-boxen というひな形プロジェクトがあるのでそれをコピーします。自分は Fork してしまいました。Fork したら git clone して編集できるように手元におきます。今回は ~/gitrepos/our-boxen に clone しておくことにします。

$ git clone git@github.com:{your_name}/our-boxen.git ~/gitrepos/out-boxen

でかいというか歴史があるのか clone に結構時間かかりますね (υ´Д`) 中にあるファイルはこんなかんじです。

├── Gemfile
├── Gemfile.lock
├── LICENSE
├── Puppetfile
├── Puppetfile.lock
├── README.md
├── config
│   ├── basic.rb
│   └── boxen.rb
├── docs
│   ├── faq.md
│   ├── modules.md
│   ├── personal-configuration.md
│   ├── puppet.md
│   └── rails.md
├── lib
├── manifests
│   └── site.pp
├── modules
│   ├── people
│   └── projects
├── script
│   ├── bootstrap
│   ├── boxen
│   ├── boxen-bootstrap
│   ├── boxen-git-credential
│   ├── boxen-my-config
│   ├── nuke
│   └── sync
├── shared
│   └── README.md
└── vendor
    ├── cache
    ├── puppet
    └── shims

2. Puppetfile の編集

https://github.com/boxen 以下に puppet-* というレポジトリ名の Boxen モジュールがたくさんあるので、その github 情報を Puppetfile に追加して、モジュールを定義します。

# Core modules for a basic development environment. You can replace
# some/most of these if you want, but it's not recommended.

github "autoconf",   "1.0.0"
github "dnsmasq",    "1.0.0"
github "gcc",        "2.0.1"
github "git",        "1.2.5"
github "homebrew",   "1.4.1"
github "hub",        "1.0.3"
github "inifile",    "1.0.0", :repo => "puppetlabs/puppetlabs-inifile"
github "nginx",      "1.4.2"
github "nodejs",     "3.2.9"
github "openssl",    "1.0.0"
github "repository", "2.2.0"
github "ruby",       "6.3.4"
github "stdlib",     "4.1.0", :repo => "puppetlabs/puppetlabs-stdlib"
github "sudo",       "1.0.0"
github "xquartz",    "1.1.0"

# Optional/custom modules. There are tons available at
# https://github.com/boxen.

github "chrome", "1.1.1" # 追加してみた!

chrome の定義を最下行に追加してみました。"1.1.1" というのは github レポジトリ https://github.com/boxen/puppet-chrome 上のタグで、github レポジトリを覗いて調べて記述するようです。# Gemfile と違って必ず指定しないといけないようですね。めんどくさいな。。。

また、上のほうに、デフォルトで nginx や xquartz などが定義されていますが、これらは Boxen 自体が使うので消さない方が良いとのことです。消せるかもしれないが、オススメしないとのことです。この定義で即インストールされるわけではないので、このままにしておきましょう。

なお、boxen レポジトリを覗いていて puppet-screen はあるけど、puppet-tmux がない!作らないといけないのか!と1度思いましたが、homebrew でインストールできるものに対しては puppet manifest を用意するまでもないようです。後述します。

3. manifests/site.pp の編集

Puppetfile の編集はあくまで github 情報の定義であり、これでアプリがインストールされるわけではありません。デフォルトで定義されていた Boxen モジュールのインストールは manifests/site.pp ファイルに記述されています。

基本的にはそのままで良いのですが、「これはちょっと入れて欲しくないなー」という場合は編集しましょう。例えば nginx とか、nodejs、ruby の古いバージョンは要らない、という場合は以下のようにコメントアウトしてしまいましょう。

# manifests/site.pp
…

node default {
  # core modules, needed for most things
  include dnsmasq
  include git
  include hub
  # include nginx # コメントアウトした

  # fail if FDE is not enabled
  if $::root_encrypted == 'no' {
    fail('Please enable full disk encryption and try again')
  }

  # node versions
  #include nodejs::v0_4 # コメントアウトした
  #include nodejs::v0_6 # コメントアウトした
  #include nodejs::v0_8 # コメントアウトした
  include nodejs::v0_10

  # default ruby versions
  #include ruby::1_8_7 # コメントアウトした
  #include ruby::1_9_2 # コメントアウトした
  #include ruby::1_9_3 # コメントアウトした
  include ruby::2_0_0

...

4. 個人用 manifest の用意

boxen は our-boxen というレポジトリ名の通り、チーム(our)で1つのレポジトリを使う事を想定しているようです。今回私は個人で使うつもりなんですが、いちおう流儀に乗っ取っとって進めることにします。

個人用の manifest を用意したい場合には manifests/people/manifests/{githubのログイン名}.pp というファイルを作る流儀なようです。私の場合は sonots.pp ですね。

以下のようにしてみました。homebrew で tmux などをインストールしているのと、github の自分のアカウントから dotfiles レポジトリを clone してきて、中に置いている install.sh スクリプトを走らせるなどします。

# manifests/people/manifests/sonots.pp
class people::sonots {
  include chrome # Puppetfile で定義したもの

  # homebrew でインストールするもの
  package {
    [
      'tmux',
      'reattach-to-user-namespace',
      'tree',
      'pidof',
      'ctags',
    ]:
  }

  $home     = "/Users/${::boxen_user}"
  $dotfiles = "${home}/.dotfiles"

  file { $home:
    ensure  => directory
  }

  # git clone git@github.com:sonots/dotfiles.git
  repository { $dotfiles:
    source  => 'sonots/dotfiles',
    require => File[$home]
  }

  # git-cloneしたら install.sh を走らせる
  exec { "sh ${dotfiles}/install.sh":
    cwd => $dotfiles,
    creates => "${home}/.zshrc",
    require => Repository[$dotfiles],
  }
}

5. 実行

では実行してみましょう! Boxen はデフォルトではディスクの暗号化を要求するので、有効にします。

システム設定 → セキュリティとプライバシー → FileVault から有効にします。

無効のまま使いたい場合は --no-fde オプションを指定すればOKです。

$ script/boxen
# script/boxen --no-fde # 暗号化を使わない場合
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/bin]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/data]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/data/project-sockets]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/data/puppet]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/log]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/Users/sonots/src]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/env.d]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/env.d/config.sh]/ensure: defined content as '{md5}0768d0c248c251eed7d5b90381c4cc09'
Notice: /Stage[main]/Boxen::Sudoers/Sudoers[launchctl]/ensure: created
Notice: /Stage[main]/Ruby/File[/opt/boxen/env.d/rbenv.sh]/ensure: defined content as '{md5}7844e3de3760b9e13ca6060947f0e582'
Notice: /Stage[main]/Boxen::Sudoers/Sudoers[boxen]/ensure: created
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/README.md]/ensure: defined content as '{md5}36be20bef1e05e4d42bf2243c0ff4368'
Notice: /Stage[main]/Boxen::Config/File[/opt/boxen/env.sh]/ensure: defined content as '{md5}74eb6f01094e2f3888bd4121d25d16eb'
….

なんか色々インストールされたーー ヽ(・∀・)ノ

/opt/boxen/env.sh というファイルができて、それを利用すると boxen でいれたアプリへのパスが通るようです。.zshrc や .bashrc に

[ -f /opt/boxen/env.sh ] && source /opt/boxen/env.sh

を追記して exec $SHELL -L しておきましょう。

2013/10/28追記: boxen の削除をするには script/nuke を利用します。

$ script/nuke --all

とかですね。

まとめ

Boxen を試してみました。基本的には git clone して script/boxen するだけで動いたのですごいお手軽感がありますね。

manifest も homebrew で入れるアプリなら1行足せば良いだけですし、dmg なアプリをインストールする場合でも例えばpuppet-chrome を見ると

# init.pp
class chrome {
  package { 'Chrome':
    provider => 'appdmg',
    source   => 'https://dl.google.com/chrome/mac/stable/GoogleChrome.dmg',
  }
}

こんな puppet manifest を書けばいいだけのようですし、他にも複雑な設定手順が必要だとしても puppet がわかってる人ならなんとでもなりそうで、柔軟度も高そうですね。

もっと情報欲しい人は README.md を直接読んでください!よーし、メモから完全移行するぞー :D

以上、@sonots でした。