2014年8月7日木曜日

capistranoでpuppetをprepareしてからapplyするまでのタスクを作った

puppetをstand aloneで使う場合、chef/knifeとは違いprepare(ツールのインストール)やapply(プロビジョニング)がリモートからできないため、capistranoのお力を拝借することになります。

今回は、このcapistranoでpuppetのprepareからマニフェストのapplyまでを行うタスクを作りました。(*)

ファイル構成はこんな感じ

puppet.rake -- 今回作成したcapistranoタスクのrakeファイル
git-ssh.sh -- privateレポジトリをsshでgit cloneするための環境設定ファイル
Debian.sh -- puppetをインストール前の事前処理をするスクリプト(apt-get用)
RedHat.sh -- puppetをインストール前の事前処理をするスクリプト(yum用)
Gemfile -- capistranoをbundle installするためのGemfile


各タスクの解説


1.rsyncで事前処理スクリプトをリモートに転送

rsyncディレクトリ以下をリモートに転送。:temp_path以下のクリアを実施。
  desc 'Rsync files'
  before :script, :rsync do
    on roles(:puppet) do |role|
      base_dir =  Pathname.new(Dir.pwd)
      user = role.user + '@' if !role.user.nil?
      target = user + role.hostname + ':'  if !role.hostname.nil?
      rsync = "/usr/bin/rsync -avzC --delete --exclude=.svn #{base_dir}/rsync/ #{target}#{fetch(:temp_path)}/"
      Kernel.system *rsync
    end
  end

2.puppetをインストール前の事前処理

apt-getまたはyumのupdateを実行し、puppetに必要なpackageをインストールする。
  desc 'Install script for packages'
  before :rbenv, :script do
    on roles(:puppet) do |role|
        if test '[ -x /usr/bin/yum ]'
          execute :sudo, "/bin/sh #{fetch(:temp_path)}/shell/RedHat.sh"
        end
        if test '[ -x /usr/bin/apt-get ]'
          execute :sudo, "/bin/sh #{fetch(:temp_path)}/shell/Debian.sh"
        end
    end
  end

3.rbenvとruby-build、bundlerのインストール

puppet自体はbundle installするためその手前までのruby環境を構築。rbenvのパスは実行時に都度指定するため環境変数には取り込まない。
  desc 'Install rbenv and bundler'
  before :apply, :rbenv do
    on roles(:puppet) do |role|
      if test "[ ! -d #{fetch(:rbenv_path)} ]"
        execute "/usr/bin/git clone https://github.com/sstephenson/rbenv.git #{fetch(:rbenv_path)}"
      end
      if test "[ ! -d #{fetch(:rbenv_path)}/plugins/ruby-build ]"
        execute "/usr/bin/git clone https://github.com/sstephenson/ruby-build.git #{fetch(:rbenv_path)}/plugins/ruby-build"
      end
      if test "[ ! -d #{fetch(:rbenv_path)}/versions/#{fetch(:rbenv_ruby)} ]"
        execute "#{fetch(:rbenv_bin)} install -v #{fetch(:rbenv_ruby)}; #{fetch(:rbenv_bin)} global #{fetch(:rbenv_ruby)}; #{fetch(:rbenv_bin)} rehash"
      end
      if test "[ ! -f #{fetch(:rbenv_path)}/versions/#{fetch(:rbenv_ruby)}/bin/bundle ]"
        execute "#{fetch(:rbenv_bin)} exec gem install bundler"
      end
    end
  end

4.puppetのインストールとマニフェストのgit clone、peppt applyまで

:temp_pathに:puppet_repoで指定したマニフェストをgit clone。bundle installでpuppetをインストールし、:manifestで指定したマニフェストでpuppet apply
  desc 'Puppet apply manifests'
  task :apply do
    on roles(:puppet) do |role|
      if test "[ ! -d #{fetch(:temp_path)}/puppet ]"
        execute "export GIT_SSH=#{fetch(:temp_path)}/shell/git-ssh.sh; /usr/bin/git clone #{fetch(:puppet_repo)} #{fetch(:temp_path)}/puppet"
      end
      execute "#{fetch(:rbenv_bin)} exec bundle install --gemfile #{fetch(:temp_path)}/puppet/Gemfile; #{fetch(:rbenv_bin)} rehash"
      execute :sudo, "#{fetch(:rbenv_path)}/shims/puppet apply --modulepath #{fetch(:temp_path)}/puppet/modules #{fetch(:temp_path)}/puppet/manifests/#{fetch(:manifest)}"
    end
  end


とこんな感じ。:puppet_repo、:manifestはstaging.rbやproduction.rbで定義する。role名はpuppet。:repo_urlは使わないので、puppetロール実行後に通常のデプロイをすることも可能。