Develop with pleasure!

福岡でCloudとかBlockchainとか。

Vagrant + AWS + Chef でサーバ構築自動化

AWS OpsWorks (DevOps アプリケーション管理・自動化) | アマゾン ウェブ サービス (AWS 日本語)を利用してサーバの構成管理をしようとしたけど、問題になったのがOpsWorksで使われるChefのバージョン。現時点で9.x系なんだけど(2013/07/25にChef 11のサポートがリリースされてる)、opscodeが公開しているcookbookには結構10.x系以上じゃないと動作しないものが多い。

一々、9.x系で動作するようにcookbookを修正するのも面倒だし、opscodeが公開している沢山のcookbookを利用せずに自前で全部書くというのも避けたい。

chefのgemを最新にするcookbookを作って、それをOpsWorksで実行してChefのバージョンを無理やり切り替えられないかとも考えたけど、OpsWorks内でのchefを含めたgemの管理にBundler使ってるので、その切り替えも難しそう。

ということで、OpsWorksはひとまず置いといて、VagrantとChef使った構成管理にしてみた。


まずVagrantのインストール

Vagrant - Downloadsからプラットフォームにあったものダウンロードしてインストール。

初期化処理

任意のディレクトリで

$ vagrant init

する。するとおなじみのVagrantfileが生成される。

続いてvagrant-aws pluginをインストール
$ vagrant plugin install vagrant-aws

mitchellh/vagrant-aws · GitHubを入れると、AWSがvagrant実行時のプロバイダとして利用可能になる。
AWSを使用するのでVagrantのBoxは本来必要無いんだけど、Vagrantfileに定義しないとエラーになるのでダミーのBoxを用意する。

$ vagrant box add aws-dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
お次はvagrant-omnibus pluginをインストール
$ vagrant plugin install vagrant-omnibus

schisamo/vagrant-omnibus · GitHubは、Vagrantが使用するBoxにChefがインストールされてない場合に、Chefのインストールをしてくれる。EC2を使うので予めChefをインストール済みのAMIを使うという方法もあるけど、都度そういったAMIをワザワザ作るのも面倒なので、このPluginでChefをインストールする。

cookbookの管理のためBerkshelfをインストール
$ gem install berkshelf

Berkshelfはcookbookの依存関係を考慮して必要なcookbookをopscodeのリポジトリからダウンロードしてきてくれる。(一々手動でcookbookをダウンロードするのは面倒なのでこういうツールは便利)利用するcookbookをBerksfileに↓な感じで定義する。

site :opscode

cookbook 'git'
cookbook 'database'
cookbook 'postgresql'
cookbook 'java'
cookbook 'tomcat'

あとRiotGames/vagrant-berkshelf · GitHubというpluginを入れるとvagrant up した際に、Berksfileに定義したcookbookを自動的に取得し処理してくれるんだけど、同じディレクトリ内にcookbookが落としてあるほうが内容確認するのに便利なのと、カスタマイズしたcookbookも合わせて利用したいので、今回はインストールしない。
↓のコマンド実行するとcookbooksというディレクトリ内にダウンロードしたcookbookが配置される。

$ berks install --path cookbooks
tty対応

VagrantがChefのcookbookに従ってパッケージをインストールする際、sshで対象サーバに接続しsudoしてインストール処理をするんだけど、この時サーバ側でrequirettyの設定(/etc/sudoers内の)が無効になっていないとエラーになる。Amazon Linuxだとデフォルトではこの設定は無効になっていないので、この設定を無効化した状態でAMIを作るかVagrantのコアの挙動を変更する方法 | Ryuzee.comで紹介されている方法でvagrant側のロジックを修正する必要がある。(Vagrant本家が対応しても良さそうなのにね…)

Vagrantfileの設定

↓な感じで設定。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

  # EC2を使うのでboxは使わないんだけど無いとエラーになるのでdummyのBoxを定義
  config.vm.box = "aws-dummy"
  # omnibus pluginでEC2にインストールするChefのバージョンを定義
  config.omnibus.chef_version = "11.4.4"

  config.vm.provider :aws do |aws, override|
    aws.access_key_id = 'AWSのアクセスキー'
    aws.secret_access_key = 'AWSのシークレットアクセスキー'
    aws.keypair_name = 'EC2のkeypair名'
    override.ssh.username = 'ec2-user'
    override.ssh.private_key_path = 'aws.keypair_nameで指定したkeypairのファイルパス'
    aws.instance_type = 'm1.small'
    aws.region = 'ap-northeast-1' # Tokykoリージョン指定
    aws.ami = '使用するAMI'
    aws.availability_zone = 'ap-northeast-1c' # AZ
    aws.security_groups = ['適用するAWSのSecurityGroup']
  end

  config.vm.provision :chef_solo do |chef|
    # berkshelfでDLしたopscodeのcookbooksと個別カスタマイズしたcookbookはsite-cookbooksに配置
    chef.cookbooks_path = ["./cookbooks", "./site-cookbooks"]
    chef.add_recipe "git"
    chef.add_recipe "postgresql::server"
    chef.add_recipe "java"
    chef.add_recipe "tomcat"

    # cookbook側に渡すカスタムjsonデータ
    chef.json = {
      :postgresql => {
        :dir => '/var/lib/pgsql9/data'
      },
      :java => {
        :jdk_version => 7,
        :install_flavor => 'oracle',
        :oracle => {:accept_oracle_download_terms => true}
      },
      :tomcat => {:base_version => 7}
    }
  end

  config.ssh.max_tries = 40
  config.ssh.timeout   = 120

end

JavaTomcatはソースパッケージの解凍時のエラーとかTomcatの再起動タスクのキューが溜まって予期せぬリターンコードが返ってきてエラーになるのでオリジナルのcookbookをカスタマイズした…)

起動!

準備が整ったらproviderを指定して起動する。ちなみにvagrant-awsは現状reload,resume,suspend,haltといったコマンドにはまだ対応していない。

$ vagrant up --provider=aws

全てエラー出ずに終了するとちょっと感動するw

デバッグ

定義したcookbookが何事もなく全て正常に終了するにこしたことは無いけど、まぁそんな事は無いわけで。エラーが発生した際にちょこっとcookbookを修正してデバッグしてみたくなったりする。でもちょっとした修正を適用するために毎回EC2に起動するのもちょっと…となるので、そういう場合はレシピが実行された後のインスタンスSSHでログインしてchef-soloで個別にcookbookの適用する方がお手軽。
vagrant upするとcookbook等が/tmp/vagrant-chef-1 に配備される。こののディレクトリ直下のsolo.rbがchef-soloのコンフィグレーションファイルで、dna.jsonにVagrantfileに定義した適用するrecipeやカスタムjsonデータが定義されてる。dna.jsonに定義されてるrun_listを適用したいrecipeだけにしてchef-soloを実行するとちょっとした動作確認がお手軽にできる。

$ sudo chef-solo -c solo.rb -j dna.json


今回はAWSで起動したけど、Vagrantを使った構成だと通常のBoxを使った環境とかでもそのまま適用可能になるのが便利ね。