ChefでUbuntuにnvmを入れてnode.jsのバージョンを管理する(Ubuntu12.04)


Chefでnode.jsを入れる話と、その際に苦労した話。

Ubuntuにnode.jsを入れる方法それぞれ

1. apt-getで標準リポジトリから入れる

  • 標準リポジトリで入るnodeのバージョン古すぎる
  • コマンド名がnodejsになるのでnpmの実行でこける
  • 回避方法はあるが面倒そう
  • ので、不採用

2. ppa(personal package archives)で入れる

  • バージョンの切り替えが大変そうなので不採用

3. nvmで入れる

  • 新しいバージョンも入るしバージョン切り替えも楽そうなので採用

Chefでnvmからnode.jsを入れる

最終的には以下のようなコードで動いた。

recipes/default.rb

# 標準パッケージのnodejsが入っていた場合はアンインストール
apt_repository "nodejs" do
  action :remove
  only_if { ::File.exists?("/usr/bin/nodejs") }
end

# nvmインストール
git "/usr/local/nvm" do
  repository "git://github.com/creationix/nvm.git"
  reference "master"
  action :sync
end

template "/etc/profile.d/nvm.sh" do
  source "nvm.sh.erb"
  mode 00644
end

# nvm listした際のエラー回避
directory '/usr/local/nvm/alias' do
  action :create
end

directory '/usr/local/nvm' do
  owner 'root'
  group 'root'
  mode '0755'
  action :create
end

bash "install nodejs" do
  code <<-EOC
    source /usr/local/nvm/nvm.sh
    nvm install #{node["versions"]["nodejs"]}
  EOC
  creates "/usr/local/nvm/#{node["versions"]["nodejs"]}"
end

# npm install
%w{grunt-cli redis-commander cmdparser browserify-middleware readline-browserify}.each do |p|
  bash "npm install" do
    code <<-EOC
      source /usr/local/nvm/nvm.sh
      npm install -g grunt-cli
    EOC
    not_if "npm -g ls 2> /dev/null | grep '^[├└]─[─┬] #{p}@'"
  end
end


ハマったところ

Chefではリソース毎に設定される環境変数は閉じている(正確にいえば、リソース内で環境変数を設定する場合はchefのコードとして明示的に記述する必要がある)。

上記を知らなかったために苦労した。

例えば

template "/etc/profile.d/nvm.sh" do
  source "nvm.sh.erb"
  mode 00644
end

上記でnvmをセットアップするシェルを読み込んでいるが、

bash "install nodejs" do
  code <<-EOC
    source /usr/local/nvm/nvm.sh
    nvm install #{node["versions"]["nodejs"]}
  EOC
  creates "/usr/local/nvm/#{node["versions"]["nodejs"]}"
end

ここでは上記のシェルで設定された環境変数が受け継がれない。
(だからbashリソース内でnvm.shを再び読み込ませている)

上記のコードで

bash "install nodejs" do
  code <<-EOC
    nvm install #{node["versions"]["nodejs"]}
  EOC
  creates "/usr/local/nvm/#{node["versions"]["nodejs"]}"
end

と書いて実行すると、npm command not foundとなってしまう。

おしまい

たぶん基本的なことなんだろうけど、知らなかったためにつらい思いをした。